From 6a2f99b06935cf2fa563dde02d16f80a08455bf0 Mon Sep 17 00:00:00 2001 From: Cooldude2606 Date: Sun, 29 Mar 2020 22:50:21 +0100 Subject: [PATCH] Removed useless files --- config/action_buttons.lua | 4 +- config/chat_reply.lua | 2 +- config/expcore-commands/parse_roles.lua | 2 +- control.lua | 27 +- expcore/commands.lua | 2 +- expcore/common.lua | 563 ++++++++---------- expcore/roles.lua | 6 +- modules/addons/death-logger.lua | 2 +- modules/addons/discord-alerts.lua | 4 +- modules/addons/greetings.lua | 2 +- modules/addons/random-player-colours.lua | 4 +- modules/addons/scorched-earth.lua | 2 +- modules/commands/admin-chat.lua | 2 +- modules/commands/clear-inventory.lua | 2 +- modules/commands/jail.lua | 2 +- modules/commands/rainbow.lua | 2 +- modules/commands/reports.lua | 2 +- modules/commands/roles.lua | 4 +- modules/commands/warnings.lua | 2 +- modules/control/jail.lua | 2 +- modules/control/production.lua | 4 +- modules/control/warps.lua | 3 +- modules/gui/debug/_g_view.lua | 2 +- modules/gui/debug/event_view.lua | 2 +- modules/gui/debug/expcore_gui_view.lua | 2 +- modules/gui/debug/expcore_store_view.lua | 2 +- modules/gui/debug/global_view.lua | 2 +- modules/gui/debug/main_view.lua | 2 +- modules/gui/debug/model.lua | 2 +- modules/gui/debug/package_view.lua | 6 +- modules/gui/debug/redmew_global_view.lua | 2 +- modules/gui/player-list.lua | 4 +- modules/gui/rocket-info.lua | 4 +- modules/gui/science-info.lua | 2 +- modules/gui/task-list.lua | 6 +- modules/gui/warp-list.lua | 6 +- {utils => overrides}/debug.lua | 2 +- {utils => overrides}/inspect.lua | 3 +- {utils => overrides}/math.lua | 2 +- .../print_override.lua => overrides/print.lua | 7 +- .../require.lua | 3 +- .../data_stages.lua => overrides/stages.lua | 2 + {utils => overrides}/table.lua | 210 ++++++- resources/version.lua | 2 - utils/alien_evolution_progress.lua | 179 ------ {resources => utils}/color_presets.lua | 0 utils/command.lua | 326 ---------- utils/core.lua | 223 ------- utils/dump_env.lua | 32 - utils/event.lua | 2 +- utils/game.lua | 2 +- utils/player_rewards.lua | 154 ----- utils/recipe_locker.lua | 58 -- utils/redmew_settings.lua | 178 ------ utils/state_machine.lua | 119 ---- utils/timestamp.lua | 152 ----- 56 files changed, 499 insertions(+), 1846 deletions(-) rename {utils => overrides}/debug.lua (99%) rename {utils => overrides}/inspect.lua (99%) rename {utils => overrides}/math.lua (99%) rename utils/print_override.lua => overrides/print.lua (69%) rename utils/require_override.lua => overrides/require.lua (75%) rename resources/data_stages.lua => overrides/stages.lua (91%) rename {utils => overrides}/table.lua (55%) delete mode 100644 resources/version.lua delete mode 100644 utils/alien_evolution_progress.lua rename {resources => utils}/color_presets.lua (100%) delete mode 100644 utils/command.lua delete mode 100644 utils/core.lua delete mode 100644 utils/dump_env.lua delete mode 100644 utils/player_rewards.lua delete mode 100644 utils/recipe_locker.lua delete mode 100644 utils/redmew_settings.lua delete mode 100644 utils/state_machine.lua delete mode 100644 utils/timestamp.lua diff --git a/config/action_buttons.lua b/config/action_buttons.lua index b5306cf1..77ad6b9d 100644 --- a/config/action_buttons.lua +++ b/config/action_buttons.lua @@ -12,8 +12,8 @@ local Game = require 'utils.game' --- @dep utils.game local Reports = require 'modules.control.reports' --- @dep modules.control.reports local Warnings = require 'modules.control.warnings' --- @dep modules.control.warnings local Jail = require 'modules.control.jail' --- @dep modules.control.jail -local Colors = require 'resources.color_presets' --- @dep resources.color_presets -local format_chat_player_name = ext_require('expcore.common','format_chat_player_name') --- @dep expcore.common +local Colors = require 'utils.color_presets' --- @dep utils.color_presets +local format_chat_player_name = _C.ext_require('expcore.common','format_chat_player_name') --- @dep expcore.common local selected_player_store = '' local selected_action_store = '' diff --git a/config/chat_reply.lua b/config/chat_reply.lua index f1ae92a7..52eb80be 100644 --- a/config/chat_reply.lua +++ b/config/chat_reply.lua @@ -2,7 +2,7 @@ -- @config Chat-Reply local Async = require 'expcore.async' -local format_time = ext_require('expcore.common','format_time') --- @dep expcore.common +local format_time = _C.ext_require('expcore.common','format_time') --- @dep expcore.common local async_message = Async.register(function(player, message) player.print(message) diff --git a/config/expcore-commands/parse_roles.lua b/config/expcore-commands/parse_roles.lua index 20b0d51f..f6923404 100644 --- a/config/expcore-commands/parse_roles.lua +++ b/config/expcore-commands/parse_roles.lua @@ -9,7 +9,7 @@ local Commands = require 'expcore.commands' --- @dep expcore.commands local Roles = require 'expcore.roles' --- @dep expcore.roles -local auto_complete = ext_require('expcore.common','auto_complete') --- @dep expcore.common +local auto_complete = _C.ext_require('expcore.common','auto_complete') --- @dep expcore.common require 'config.expcore-commands.parse_general' Commands.add_parse('role',function(input,player,reject) diff --git a/control.lua b/control.lua index 82237d76..5658ba42 100644 --- a/control.lua +++ b/control.lua @@ -5,24 +5,17 @@ -- this file is the landing point for all scenarios please DO NOT edit directly, further comments are to aid development log('[START] -----| Explosive Gaming Scenario Loader |-----') - --- Info on the data lifecycle and how we use it: https://github.com/Refactorio/RedMew/wiki/The-data-lifecycle log('[INFO] Setting up lua environment') -require 'resources.data_stages' -_LIFECYCLE = _STAGE.control -- Control stage --- Overrides the _G.print function -require 'utils.print_override' - --- Omitting the math library is a very bad idea -require 'utils.math' - --- Global Debug and make sure our version file is registered -Debug = require 'utils.debug' --- @dep utils.debug -require 'resources.version' - --- Global require function used to extract parts of a module, because simply being in common is not good enough -ext_require = require('expcore.common').ext_require --- @dep expcore.common.ext_require +-- Require the global overrides +require 'overrides.stages' -- Data stages used in factorio, often used to test for runtime +require 'overrides.print' -- Overrides the _G.print function +require 'overrides.math' -- Omitting the math library is a very bad idea +require 'overrides.table' -- Adds alot more functions to the table module +inspect = require 'overrides.inspect' -- Used to covert any value into human readable string +Debug = require 'overrides.debug' -- Global Debug module +_C = require('expcore.common') -- _C is used to store lots of common functions expected to be used +global.expgaming_version = '6.0.0' -- The current version for exp gaming scenario -- Please go to config/file_loader.lua to edit the files that are loaded log('[INFO] Getting file loader config') @@ -52,7 +45,7 @@ end -- Override the default require; require can no longer load new scripts log('[INFO] Require Overright! No more requires can be made!') -require 'utils.require_override' +require 'overrides.require' -- Logs all errors again to make it make it easy to find log('[INFO] All files loaded with '..#errors..' errors:') diff --git a/expcore/commands.lua b/expcore/commands.lua index a0b05475..a64370ef 100644 --- a/expcore/commands.lua +++ b/expcore/commands.lua @@ -196,7 +196,7 @@ ]] local Game = require 'utils.game' --- @dep utils.game -local player_return,write_json = ext_require('expcore.common','player_return','write_json') --- @dep expcore.common +local player_return,write_json = _C.ext_require('expcore.common','player_return','write_json') --- @dep expcore.common local Commands = { defines={ -- common values are stored error like signals diff --git a/expcore/common.lua b/expcore/common.lua index 1d9ebef0..be47f8dd 100644 --- a/expcore/common.lua +++ b/expcore/common.lua @@ -4,52 +4,276 @@ @alias Common ]] -local Colours = require 'resources.color_presets' --- @dep resources.color_presets +local Colours = require 'utils.color_presets' --- @dep utils.color_presets local Game = require 'utils.game' --- @dep utils.game local Util = require 'util' --- @dep util -require 'utils.table' -require 'utils.math' +require 'overrides.table' +require 'overrides.math' local Common = {} ---- Compare types faster for faster validation of params +--- Type Checking. +-- @section typeCheck + +--- Asserts the argument is of type test_type -- @usage type_check('foo','string') -- return true -- @usage type_check('foo') -- return false -- @tparam any value the value to be tested -- @tparam[opt=nil] string test_type the type to test for if not given then it tests for nil -- @treturn boolean is v of type test_type -function Common.type_check(value,test_type) +function Common.type_check(value, test_type) return test_type and value and type(value) == test_type or not test_type and not value or false end --- Raises an error if the value is of the wrong type --- @usage type_check_error('foo','number','Value must be a number') -- will raise error "Value must be a number" +-- @usage type_error('foo','number','Value must be a number') -- will raise error "Value must be a number" -- @tparam any value the value that you want to test the type of -- @tparam string test_type the type that the value should be -- @tparam string error_message the error message that is returned -- @tparam number level the level to call the error on (level = 1 means the caller) -- @treturn boolean true if no error was called -function Common.type_check_error(value,test_type,error_message,level) +function Common.type_error(value, test_type, error_message, level) level = level and level+1 or 2 - return Common.test_type(value,test_type) or error(error_message,level) + return Common.type_check(value,test_type) or error(error_message,level) +end + +--- Asserts the argument is one of type test_types +-- @param value the variable to check +-- @param test_types the type as a table of strings +-- @treturn boolean true if value is one of test_types +function Common.multi_type_check(value, test_types) + local vtype = type(value) + for _, arg_type in ipairs(test_types) do + if vtype == arg_type then + return true + end + end + return false +end + +--- Raises an error if the value is of the wrong type +-- @usage multi_type_error('foo',{'string','table'},'Value must be a string or table') -- will raise error "Value must be a string or table" +-- @tparam any value the value that you want to test the type of +-- @tparam table test_types the type as a table of strings +-- @tparam string error_message the error message that is returned +-- @tparam number level the level to call the error on (level = 1 means the caller) +-- @treturn boolean true if no error was called +function Common.multi_type_error(value, test_types, error_message, level) + level = level and level+1 or 2 + return Common.mult_type_check(value, test_types) or error(error_message,level) end --- Raises an error when the value is the incorrect type, uses a consistent error message format --- @usage param_check('foo','number','repeat_count',2) -- will raise error "Invalid param #02 given to ; repeat_count is not of type number" +-- @usage validate_argument_type('foo','number','repeat_count',2) -- will raise error "Bad argument #02 to ""; "repeat_count" is of type string expected number" -- @tparam any value the value that you want to test the type of -- @tparam string test_type the type that the value should be -- @tparam string param_name the name of the param -- @tparam number param_number the number param it is -- @treturn boolean true if no error was raised -function Common.param_check(value,test_type,param_name,param_number) +function Common.validate_argument_type(value, test_type, param_name, param_number) if not Common.test_type(value,test_type) then local function_name = debug.getinfo(2,'n').name or '' - local error_message = string.format('Invalid param #%2d given to %s; %s is not of type %s',param_number,function_name,param_name,test_type) + local error_message = string.format('Bad argument #%2d to %q; %q is of type %s expected %s', param_number, function_name, param_name, type(value), test_type) return error(error_message,3) end return true end +--- Raises an error when the value is the incorrect type, uses a consistent error message format +-- @usage validate_argument_type('foo',{'string','table'},'repeat_count',2) -- will raise error "Bad argument #02 to ""; "repeat_count" is of type string expected string or table" +-- @tparam any value the value that you want to test the type of +-- @tparam string test_types the types that the value should be +-- @tparam string param_name the name of the param +-- @tparam number param_number the number param it is +-- @treturn boolean true if no error was raised +function Common.validate_argument_multi_type(value, test_types, param_name, param_number) + if not Common.multi_type_check(value,test_types) then + local function_name = debug.getinfo(2,'n').name or '' + local error_message = string.format('Bad argument #%2d to %q; %q is of type %s expected %s', param_number, function_name, param_name, type(value), table.concat(test_types,' or ')) + return error(error_message,3) + end + return true +end + +--- Value Returns. +-- @section valueReturns + +--- Tests if a string contains a given substring. +-- @tparam string s the string to check for the substring +-- @tparam string contains the substring to test for +-- @treturn boolean true if the substring was found in the string +function Common.string_contains(s, contains) + return s and string.find(s, contains) ~= nil +end + +--[[-- Used to resolve a value that could also be a function returning that value +@tparam any value the value which you want to test is not nil and if it is a function then call the function +@treturn any the value given or returned by value if it is a function +@usage-- Default value handling +-- if default value is not a function then it is returned +-- if it is a function then it is called with the first argument being self +local value = Common.resolve_value(self.defaut_value,self) +]] +function Common.resolve_value(value,...) + if value then + if type(value) == 'function' then + return value(...) + else + return value + end + end +end + +--- Returns a valid string with the name of the actor of a command. +-- @treturns string the name of the current actor +function Common.get_actor() + return game.player and game.player.name or '' +end + +--- Converts a varible into its boolean value, nil and false return false +-- @treturn boolean the boolean form of the varible +function Common.cast_bool(var) + return var and true or false +end + +--- Returns either the second or third argument based on the first argument +function Common.ternary(c, t, f) + return c and t or f +end + +--- Returns a string for a number with comma seperators +function Common.comma_value(n) -- credit http://richard.warburton.it + local left, num, right = string.match(n, '^([^%d]*%d)(%d*)(.-)$') + return left .. (num:reverse():gsub('(%d%d%d)', '%1,'):reverse()) .. right +end + +--- Sets a table element to value while also returning value. +-- @param tbl table to change the element of +-- @param key string +-- @param value nil|boolean|number|string|table to set the element to +-- @return value +function Common.set_and_return(tbl, key, value) + tbl[key] = value + return value +end + +--- Writes a table object to a file in json format +-- @tparam string path the path of the file to write include / to use dir +-- @tparam table tbl the table that will be converted to a json string and wrote to file +function Common.write_json(path,tbl) + game.write_file(path,game.table_to_json(tbl)..'\n',true,0) +end + +--- Calls a require that will not error if the file is not found +-- @usage local file = opt_require('file.not.present') -- will not cause any error +-- @tparam string path the path that you want to require +-- @return the returns from that file or nil, error if not loaded +function Common.opt_require(path) + local success, rtn = pcall(require,path) + if success then return rtn + else return nil,rtn end +end + +--- Calls a require and returns only the keys given, file must return a table +-- @usage local extract, param_check = _C.ext_require('expcore.common','extract','param_check') --- @dep expcore.common +-- @tparam string path the path that you want to require +-- @tparam string ... the name of the keys that you want returned +-- @return the keys in the order given +function Common.ext_require(path,...) + local rtn = require(path) + if type(rtn) ~= 'table' then + error('File did not return a table, can not extract keys.',2) + end + return table.extract_keys(rtn,...) +end + +--- Returns a desync safe file path for the current file +-- @tparam[opt=0] number offset the offset in the stack to get, 0 is current file +-- @treturn string the file path +function Common.get_file_path(offset) + offset = offset or 0 + return debug.getinfo(offset+2, 'S').source:match('^.+/currently%-playing/(.+)$'):sub(1, -5) +end + +--- Converts a table to an enum +-- @tparam table tbl table the that will be converted +-- @treturn table the new table that acts like an enum +function Common.enum(tbl) + local rtn = {} + for k,v in pairs(tbl) do + if type(k) ~= 'number' then + rtn[v]=k + end + end + for k,v in pairs(tbl) do + if type(k) == 'number' then + table.insert(rtn,v) + end + end + for k,v in pairs(rtn) do + rtn[v]=k + end + return rtn +end + +--- Returns the closest match to the input +-- @tparam table options table a of options for the auto complete +-- @tparam string input string the input that will be completed +-- @tparam[opt=false] boolean use_key when true the keys of options will be used as the options +-- @tparam[opt=false] boolean rtn_key when true the the key will be returned rather than the value +-- @return the list item found that matches the input +function Common.auto_complete(options,input,use_key,rtn_key) + local rtn = {} + if type(input) ~= 'string' then return end + input = input:lower() + for key,value in pairs(options) do + local check = use_key and key or value + if Common.string_contains(string.lower(check),input) then + local result = rtn_key and key or value + table.insert(rtn,result) + end + end + return rtn[1] +end + +--- Formating. +-- @section formating + +--- Returns a message with valid chat tags to change its colour +-- @tparam string message the message that will be in the output +-- @tparam table color a color which contains r,g,b as its keys +-- @treturn string the message with the color tags included +function Common.format_chat_colour(message,color) + color = color or Colours.white + local color_tag = '[color='..math.round(color.r,3)..','..math.round(color.g,3)..','..math.round(color.b,3)..']' + return string.format('%s%s[/color]',color_tag,message) +end + +--- Returns a message with valid chat tags to change its colour, using localization +-- @tparam ?string|table message the message that will be in the output +-- @tparam table color a color which contains r,g,b as its keys +-- @treturn table the message with the color tags included +function Common.format_chat_colour_localized(message,color) + color = color or Colours.white + color = math.round(color.r,3)..','..math.round(color.g,3)..','..math.round(color.b,3) + return {'color-tag',color,message} +end + +--- Returns the players name in the players color +-- @tparam LuaPlayer player the player to use the name and color of +-- @tparam[opt=false] boolean raw_string when true a is returned rather than a localized string +-- @treturn table the players name with tags for the players color +function Common.format_chat_player_name(player,raw_string) + player = Game.get_player_from_any(player) + local player_name = player and player.name or '' + local player_chat_colour = player and player.chat_color or Colours.white + if raw_string then + return Common.format_chat_colour(player_name,player_chat_colour) + else + return Common.format_chat_colour_localized(player_name,player_chat_colour) + end +end + --- Will return a value of any type to the player/server console, allows colour for in-game players -- @usage player_return('Hello, World!') -- returns 'Hello, World!' to game.player or server console -- @usage player_return('Hello, World!','green') -- returns 'Hello, World!' to game.player with colour green or server console @@ -91,36 +315,6 @@ function Common.player_return(value,colour,player) else rcon.print(returnAsString) end end ---- Writes a table object to a file in json format --- @tparam string path the path of the file to write include / to use dir --- @tparam table tbl the table that will be converted to a json string and wrote to file -function Common.write_json(path,tbl) - game.write_file(path,game.table_to_json(tbl)..'\n',true,0) -end - ---- Calls a require that will not error if the file is not found --- @usage local file = opt_require('file.not.present') -- will not cause any error --- @tparam string path the path that you want to require --- @return the returns from that file or nil, error if not loaded -function Common.opt_require(path) - local success, rtn = pcall(require,path) - if success then return rtn - else return nil,rtn end -end - ---- Calls a require and returns only the keys given, file must return a table --- @usage local extract, param_check = ext_require('expcore.common','extract','param_check') --- @dep expcore.common --- @tparam string path the path that you want to require --- @tparam string ... the name of the keys that you want returned --- @return the keys in the order given -function Common.ext_require(path,...) - local rtn = require(path) - if type(rtn) ~= 'table' then - error('File did not return a table, can not extract keys.',2) - end - return Common.extract_keys(rtn,...) -end - --- Formats tick into a clean format, denominations from highest to lowest -- long will use words rather than letters -- time will use : separates @@ -213,6 +407,9 @@ function Common.format_time(ticks,options) return rtn end +--- Factorio. +-- @section factorio + --- Moves items to the position and stores them in the closest entity of the type given -- @tparam table items items which are to be added to the chests, ['name']=count -- @tparam[opt=navies] LuaSurface surface the surface that the items will be moved to @@ -416,288 +613,4 @@ function Common.clear_flying_text(surface) end end ---- Tests if a string contains a given substring. --- @tparam string s the string to check for the substring --- @tparam string contains the substring to test for --- @treturn boolean true if the substring was found in the string -function Common.string_contains(s, contains) - return s and string.find(s, contains) ~= nil -end - ---- Extracts certain keys from a table --- @usage local key_three, key_one = extract({key_one='foo',key_two='bar',key_three=true},'key_three','key_one') --- @tparam table tbl table the which contains the keys --- @tparam string ... the names of the keys you want extracted --- @return the keys in the order given -function Common.extract_keys(tbl,...) - local values = {} - for _,key in pairs({...}) do - table.insert(values,tbl[key]) - end - return unpack(values) -end - ---- Converts a table to an enum --- @tparam table tbl table the that will be converted --- @treturn table the new table that acts like an enum -function Common.enum(tbl) - local rtn = {} - for k,v in pairs(tbl) do - if type(k) ~= 'number' then - rtn[v]=k - end - end - for k,v in pairs(tbl) do - if type(k) == 'number' then - table.insert(rtn,v) - end - end - for k,v in pairs(rtn) do - rtn[v]=k - end - return rtn -end - ---- Returns the closest match to the input --- @tparam table options table a of options for the auto complete --- @tparam string input string the input that will be completed --- @tparam[opt=false] boolean use_key when true the keys of options will be used as the options --- @tparam[opt=false] boolean rtn_key when true the the key will be returned rather than the value --- @return the list item found that matches the input -function Common.auto_complete(options,input,use_key,rtn_key) - local rtn = {} - if type(input) ~= 'string' then return end - input = input:lower() - for key,value in pairs(options) do - local check = use_key and key or value - if Common.string_contains(string.lower(check),input) then - local result = rtn_key and key or value - table.insert(rtn,result) - end - end - return rtn[1] -end - ---- Default table comparator sort function. --- @local --- @param x one comparator operand --- @param y the other comparator operand --- @return true if x logically comes before y in a list, false otherwise -local function sortFunc(x, y) --sorts tables with mixed index types. - local tx = type(x) - local ty = type(y) - if tx == ty then - if type(x) == 'string' then - return string.lower(x) < string.lower(y) - else - return x < y - end - elseif tx == 'number' then - return true --only x is a number and goes first - else - return false --only y is a number and goes first - end -end - ---- Returns a copy of all of the values in the table. --- @tparam table tbl the to copy the keys from, or an empty table if tbl is nil --- @tparam[opt] boolean sorted whether to sort the keys (slower) or keep the random order from pairs() --- @tparam[opt] boolean as_string whether to try and parse the values as strings, or leave them as their existing type --- @treturn array an array with a copy of all the values in the table -function Common.table_values(tbl, sorted, as_string) - if not tbl then return {} end - local valueset = {} - local n = 0 - if as_string then --checking as_string /before/ looping is faster - for _, v in pairs(tbl) do - n = n + 1 - valueset[n] = tostring(v) - end - else - for _, v in pairs(tbl) do - n = n + 1 - valueset[n] = v - end - end - if sorted then - table.sort(valueset,sortFunc) - end - return valueset -end - ---- Returns a copy of all of the keys in the table. --- @tparam table tbl the to copy the keys from, or an empty table if tbl is nil --- @tparam[opt] boolean sorted whether to sort the keys (slower) or keep the random order from pairs() --- @tparam[opt] boolean as_string whether to try and parse the keys as strings, or leave them as their existing type --- @treturn array an array with a copy of all the keys in the table -function Common.table_keys(tbl, sorted, as_string) - if not tbl then return {} end - local keyset = {} - local n = 0 - if as_string then --checking as_string /before/ looping is faster - for k, _ in pairs(tbl) do - n = n + 1 - keyset[n] = tostring(k) - end - else - for k, _ in pairs(tbl) do - n = n + 1 - keyset[n] = k - end - end - if sorted then - table.sort(keyset,sortFunc) - end - return keyset -end - ---- Returns the list is a sorted way that would be expected by people (this is by key) --- @tparam table tbl the table to be sorted --- @treturn table the sorted table -function Common.table_alphanumsort(tbl) - local o = Common.table_keys(tbl) - local function padnum(d) local dec, n = string.match(d, "(%.?)0*(.+)") - return #dec > 0 and ("%.12f"):format(d) or ("%s%03d%s"):format(dec, #n, n) end - table.sort(o, function(a,b) - return tostring(a):gsub("%.?%d+",padnum)..("%3d"):format(#b) - < tostring(b):gsub("%.?%d+",padnum)..("%3d"):format(#a) end) - local _tbl = {} - for _,k in pairs(o) do _tbl[k] = tbl[k] end - return _tbl -end - ---- Returns the list is a sorted way that would be expected by people (this is by key) (faster alternative than above) --- @tparam table tbl the table to be sorted --- @treturn table the sorted table -function Common.table_keysort(tbl) - local o = Common.table_keys(tbl,true) - local _tbl = {} - for _,k in pairs(o) do _tbl[k] = tbl[k] end - return _tbl -end - ---- Returns a message with valid chat tags to change its colour --- @tparam string message the message that will be in the output --- @tparam table color a color which contains r,g,b as its keys --- @treturn string the message with the color tags included -function Common.format_chat_colour(message,color) - color = color or Colours.white - local color_tag = '[color='..math.round(color.r,3)..','..math.round(color.g,3)..','..math.round(color.b,3)..']' - return string.format('%s%s[/color]',color_tag,message) -end - ---- Returns a message with valid chat tags to change its colour, using localization --- @tparam ?string|table message the message that will be in the output --- @tparam table color a color which contains r,g,b as its keys --- @treturn table the message with the color tags included -function Common.format_chat_colour_localized(message,color) - color = color or Colours.white - color = math.round(color.r,3)..','..math.round(color.g,3)..','..math.round(color.b,3) - return {'color-tag',color,message} -end - ---- Returns the players name in the players color --- @tparam LuaPlayer player the player to use the name and color of --- @tparam[opt=false] boolean raw_string when true a is returned rather than a localized string --- @treturn table the players name with tags for the players color -function Common.format_chat_player_name(player,raw_string) - player = Game.get_player_from_any(player) - local player_name = player and player.name or '' - local player_chat_colour = player and player.chat_color or Colours.white - if raw_string then - return Common.format_chat_colour(player_name,player_chat_colour) - else - return Common.format_chat_colour_localized(player_name,player_chat_colour) - end -end - ---- Returns a desync safe file path for the current file --- @tparam[opt=0] number offset the offset in the stack to get, 0 is current file --- @treturn string the file path -function Common.get_file_path(offset) - offset = offset or 0 - return debug.getinfo(offset+2, 'S').source:match('^.+/currently%-playing/(.+)$'):sub(1, -5) -end - ---[[-- Much faster method for inserting items into an array -@tparam table tbl the table that will have the values added to it -@tparam[opt] number start_index the index at which values will be added, nil means end of the array -@tparam table values the new values that will be added to the table -@treturn table the table that was passed as the first argument -@usage-- Adding 1000 values into the middle of the array -local tbl = {} -local values = {} -for i = 1,1000 do tbl[i] = i values[i] = i end -Common.array_insert(tbl,500,values) -- around 0.4ms -]] -function Common.array_insert(tbl,start_index,values) - if not values then - values = start_index - start_index = nil - end - - if start_index then - local starting_length = #tbl - local adding_length = #values - local move_to = start_index+adding_length+1 - for offset = starting_length-start_index, 0, -1 do - tbl[move_to+offset] = tbl[starting_length+offset] - end - start_index = start_index-1 - else - start_index = #tbl - end - - for offset, item in ipairs(values) do - tbl[start_index+offset] = item - end - - return tbl -end - ---[[-- Much faster method for inserting keys into a table -@tparam table tbl the table that will have keys added to it -@tparam[opt] number start_index the index at which values will be added, nil means end of the array, numbered indexs only -@tparam table tbl2 the table that may contain both string and numbered keys -@treturn table the table passed as the first argument -@usage-- Merging two tables -local tbl = {} -local tbl2 = {} -for i = 1,100 do tbl[i] = i tbl['_'..i] = i tbl2[i] = i tbl2['__'..i] = i end -Common.table_insert(tbl,50,tbl2) -]] -function Common.table_insert(tbl,start_index,tbl2) - if not tbl2 then - tbl2 = start_index - start_index = nil - end - - Common.array_insert(tbl,start_index,tbl2) - for key, value in pairs(tbl2) do - if not tonumber(key) then - tbl[key] = value - end - end - - return tbl -end - ---[[-- Used to resolve a value that could also be a function returning that value -@tparam any value the value which you want to test is not nil and if it is a function then call the function -@treturn any the value given or returned by value if it is a function -@usage-- Default value handling --- if default value is not a function then it is returned --- if it is a function then it is called with the first argument being self -local value = Common.resolve_value(self.defaut_value,self) -]] -function Common.resolve_value(value,...) - if value then - if type(value) == 'function' then - return value(...) - else - return value - end - end -end - return Common \ No newline at end of file diff --git a/expcore/roles.lua b/expcore/roles.lua index 1163d84b..11616822 100644 --- a/expcore/roles.lua +++ b/expcore/roles.lua @@ -117,8 +117,8 @@ local Global = require 'utils.global' --- @dep utils.global local Event = require 'utils.event' --- @dep utils.event local Groups = require 'expcore.permission_groups' --- @dep expcore.permission_groups local Async = require 'expcore.async' --- @dep expcore.async -local Colours = require 'resources.color_presets' --- @dep resources.color_presets -local write_json = ext_require('expcore.common','write_json') --- @dep expcore.common +local Colours = require 'utils.color_presets' --- @dep utils.color_presets +local write_json = _C.ext_require('expcore.common','write_json') --- @dep expcore.common local Roles = { _prototype={}, @@ -437,7 +437,7 @@ function Roles.define_role_order(order) end end -- Check no roles were missed - for role_name,_ in pairs(Role.config.roles) do + 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 diff --git a/modules/addons/death-logger.lua b/modules/addons/death-logger.lua index fb188f82..6f4be5d7 100644 --- a/modules/addons/death-logger.lua +++ b/modules/addons/death-logger.lua @@ -5,7 +5,7 @@ local Event = require 'utils.event' --- @dep utils.event local Game = require 'utils.game' --- @dep utils.game local Global = require 'utils.global' --- @dep utils.global local config = require 'config.death_logger' --- @dep config.death_logger -local format_time,move_items = ext_require('expcore.common','format_time','move_items') --- @dep expcore.common +local format_time,move_items = _C.ext_require('expcore.common','format_time','move_items') --- @dep expcore.common local deaths = { archive={} -- deaths moved here after body is gone diff --git a/modules/addons/discord-alerts.lua b/modules/addons/discord-alerts.lua index 5aabc77e..22bba566 100644 --- a/modules/addons/discord-alerts.lua +++ b/modules/addons/discord-alerts.lua @@ -3,8 +3,8 @@ local Event = require 'utils.event' --- @dep utils.event local Game = require 'utils.game' --- @dep utils.game -local Colors = require 'resources.color_presets' --- @dep resources.color_presets -local write_json,format_time = ext_require('expcore.common','write_json','format_time') --- @dep expcore.common +local Colors = require 'utils.color_presets' --- @dep utils.color_presets +local write_json,format_time = _C.ext_require('expcore.common','write_json','format_time') --- @dep expcore.common local config = require 'config.discord_alerts' --- @dep config.discord_alerts local function get_player_name(event) diff --git a/modules/addons/greetings.lua b/modules/addons/greetings.lua index df625656..068e33e7 100644 --- a/modules/addons/greetings.lua +++ b/modules/addons/greetings.lua @@ -4,7 +4,7 @@ local Event = require 'utils.event' --- @dep utils.event local Game = require 'utils.game' --- @dep utils.event local config = require 'config.join_messages' --- @dep config.join_messages local Global = require 'utils.global' --- @dep utils.global -require 'utils.table' +require 'overrides.table' Global.register(config,function(tbl) config = tbl diff --git a/modules/addons/random-player-colours.lua b/modules/addons/random-player-colours.lua index 0677faa1..30526f20 100644 --- a/modules/addons/random-player-colours.lua +++ b/modules/addons/random-player-colours.lua @@ -1,12 +1,12 @@ --- Gives players random colours when they join, also applies preset colours to those who have them -- @addon Player-Colours -local Colours = require 'resources.color_presets' --- @dep resources.color_presets +local Colours = require 'utils.color_presets' --- @dep utils.color_presets local Game = require 'utils.game' --- @dep utils.game local Event = require 'utils.event' --- @dep utils.event local config = require 'config.preset_player_colours' --- @dep config.preset_player_colours local Global = require 'utils.global' --- @dep utils.global -require 'utils.table' +require 'overrides.table' Global.register(config,function(tbl) config = tbl diff --git a/modules/addons/scorched-earth.lua b/modules/addons/scorched-earth.lua index 82c361de..9ae946f5 100644 --- a/modules/addons/scorched-earth.lua +++ b/modules/addons/scorched-earth.lua @@ -4,7 +4,7 @@ local Event = require 'utils.event' --- @dep utils.event local Game = require 'utils.game' --- @dep utils.game local Global = require 'utils.global' --- @dep utils.global -local print_grid_value, clear_flying_text = ext_require('expcore.common','print_grid_value','clear_flying_text') --- @dep expcore.common +local print_grid_value, clear_flying_text = _C.ext_require('expcore.common','print_grid_value','clear_flying_text') --- @dep expcore.common local config = require 'config.scorched_earth' --- @dep config.scorched_earth -- Loops over the config and finds the wile which has the highest value for strength diff --git a/modules/commands/admin-chat.lua b/modules/commands/admin-chat.lua index 63a5447d..9a8182cb 100644 --- a/modules/commands/admin-chat.lua +++ b/modules/commands/admin-chat.lua @@ -4,7 +4,7 @@ ]] local Commands = require 'expcore.commands' --- @dep expcore.commands -local format_chat_player_name = ext_require('expcore.common','format_chat_player_name') --- @dep expcore.common +local format_chat_player_name = _C.ext_require('expcore.common','format_chat_player_name') --- @dep expcore.common require 'config.expcore-commands.parse_general' --- Sends a message in chat that only admins can see diff --git a/modules/commands/clear-inventory.lua b/modules/commands/clear-inventory.lua index 587e8ce2..91e6c7e5 100644 --- a/modules/commands/clear-inventory.lua +++ b/modules/commands/clear-inventory.lua @@ -4,7 +4,7 @@ ]] local Commands = require 'expcore.commands' --- @dep expcore.commands -local move_items = ext_require('expcore.common','move_items') --- @dep expcore.common +local move_items = _C.ext_require('expcore.common','move_items') --- @dep expcore.common require 'config.expcore-commands.parse_roles' --- Clears a players inventory diff --git a/modules/commands/jail.lua b/modules/commands/jail.lua index c6c92954..279eb373 100644 --- a/modules/commands/jail.lua +++ b/modules/commands/jail.lua @@ -5,7 +5,7 @@ local Commands = require 'expcore.commands' --- @dep expcore.commands local Jail = require 'modules.control.jail' --- @dep modules.control.jail -local format_chat_player_name = ext_require('expcore.common','format_chat_player_name') --- @dep expcore.common +local format_chat_player_name = _C.ext_require('expcore.common','format_chat_player_name') --- @dep expcore.common require 'config.expcore-commands.parse_roles' --- Puts a player into jail and removes all other roles. diff --git a/modules/commands/rainbow.lua b/modules/commands/rainbow.lua index a5c03e53..4a29fe6a 100644 --- a/modules/commands/rainbow.lua +++ b/modules/commands/rainbow.lua @@ -4,7 +4,7 @@ ]] local Commands = require 'expcore.commands' --- @dep expcore.commands -local format_chat_colour = ext_require('expcore.common','format_chat_colour') --- @dep expcore.common +local format_chat_colour = _C.ext_require('expcore.common','format_chat_colour') --- @dep expcore.common local function step_component(c1,c2) if c1 < 0 then diff --git a/modules/commands/reports.lua b/modules/commands/reports.lua index 8baaf5f3..51f2f493 100644 --- a/modules/commands/reports.lua +++ b/modules/commands/reports.lua @@ -6,7 +6,7 @@ local Roles = require 'expcore.roles' --- @dep expcore.roles local Commands = require 'expcore.commands' --- @dep expcore.commands local Reports = require 'modules.control.reports' --- @dep modules.control.reports -local format_chat_player_name = ext_require('expcore.common','format_chat_player_name') --- @dep expcore.common +local format_chat_player_name = _C.ext_require('expcore.common','format_chat_player_name') --- @dep expcore.common require 'config.expcore-commands.parse_general' --- Reports a player and notifies moderators diff --git a/modules/commands/roles.lua b/modules/commands/roles.lua index 63575732..448109f0 100644 --- a/modules/commands/roles.lua +++ b/modules/commands/roles.lua @@ -5,8 +5,8 @@ local Commands = require 'expcore.commands' --- @dep expcore.commands local Roles = require 'expcore.roles' --- @dep expcore.roles -local Colours = require 'resources.color_presets' --- @dep resources.color_presets -local format_chat_player_name, format_chat_colour_localized = ext_require('expcore.common', +local Colours = require 'utils.color_presets' --- @dep utils.color_presets +local format_chat_player_name, format_chat_colour_localized = _C.ext_require('expcore.common', 'format_chat_player_name', 'format_chat_colour_localized' ) diff --git a/modules/commands/warnings.lua b/modules/commands/warnings.lua index 2cd5509c..9c1dfcef 100644 --- a/modules/commands/warnings.lua +++ b/modules/commands/warnings.lua @@ -5,7 +5,7 @@ local Commands = require 'expcore.commands' --- @dep expcore.commands local Warnings = require 'modules.control.warnings' --- @dep modules.control.warnings -local format_chat_player_name = ext_require('expcore.common','format_chat_player_name') --- @dep expcore.common +local format_chat_player_name = _C.ext_require('expcore.common','format_chat_player_name') --- @dep expcore.common local config = require 'config.warnings' --- @dep config.warnings require 'config.expcore-commands.parse_roles' diff --git a/modules/control/jail.lua b/modules/control/jail.lua index 89c9043c..10a387a1 100644 --- a/modules/control/jail.lua +++ b/modules/control/jail.lua @@ -23,7 +23,7 @@ local Roles = require 'expcore.roles' --- @dep expcore.roles local Game = require 'utils.game' --- @dep utils.game local Global = require 'utils.global' --- @dep utils.global -local move_items = ext_require('expcore.common','move_items') --- @dep expcore.common +local move_items = _C.ext_require('expcore.common','move_items') --- @dep expcore.common local valid_player = Game.get_player_from_any local assign_roles = Roles.assign_player diff --git a/modules/control/production.lua b/modules/control/production.lua index d12c8477..16eb97b9 100644 --- a/modules/control/production.lua +++ b/modules/control/production.lua @@ -32,8 +32,8 @@ ]] -local Colors = require 'resources.color_presets' --- @dep resources.color_presets -local format_number = ext_require('util','format_number') --- @dep util +local Colors = require 'utils.color_presets' --- @dep utils.color_presets +local format_number = _C.ext_require('util','format_number') --- @dep util local precision_index = defines.flow_precision_index local Production = {} diff --git a/modules/control/warps.lua b/modules/control/warps.lua index 8958c833..93bf0ea2 100644 --- a/modules/control/warps.lua +++ b/modules/control/warps.lua @@ -25,7 +25,6 @@ local Store = require 'expcore.store' --- @dep expcore.store local Global = require 'utils.global' --- @dep utils.global local Token = require 'utils.token' --- @dep utils.token local config = require 'config.warps' --- @dep config.warps -local table_values,table_keysort = ext_require('expcore.common','table_values','table_keysort') --- @dep expcore.common local Warps = {} @@ -64,7 +63,7 @@ Store.watch(warp_store,function(warp,warp_id) end -- Sort the warp names in alphabetical order - local new_warp_ids = table_values(table_keysort(warp_names)) + local new_warp_ids = table.get_values(table.keysort(warp_names)) table.insert(new_warp_ids,1,spawn_id) new_warp_ids.spawn = spawn_id force_warps[force_name] = new_warp_ids diff --git a/modules/gui/debug/_g_view.lua b/modules/gui/debug/_g_view.lua index 33005bd2..2cf7490a 100644 --- a/modules/gui/debug/_g_view.lua +++ b/modules/gui/debug/_g_view.lua @@ -1,6 +1,6 @@ local Gui = require 'utils.gui' --- @dep utils.gui local Model = require 'modules.gui.debug.model' --- @dep modules.gui.debug.model -local Color = require 'resources.color_presets' --- @dep resources.color_presets +local Color = require 'utils.color_presets' --- @dep utils.color_presets local dump = Model.dump diff --git a/modules/gui/debug/event_view.lua b/modules/gui/debug/event_view.lua index cae93e60..b56cb34f 100644 --- a/modules/gui/debug/event_view.lua +++ b/modules/gui/debug/event_view.lua @@ -1,5 +1,5 @@ local Event = require 'utils.event' -local table = require 'utils.table' +local table = require 'overrides.table' local Gui = require 'utils.gui' local Model = require 'modules.gui.debug.model' diff --git a/modules/gui/debug/expcore_gui_view.lua b/modules/gui/debug/expcore_gui_view.lua index cf95e894..468196e4 100644 --- a/modules/gui/debug/expcore_gui_view.lua +++ b/modules/gui/debug/expcore_gui_view.lua @@ -1,6 +1,6 @@ local Gui = require 'utils.gui' --- @dep utils.gui local ExpGui = require 'expcore.gui' --- @dep utils.global -local Color = require 'resources.color_presets' --- @dep resources.color_presets +local Color = require 'utils.color_presets' --- @dep utils.color_presets local Model = require 'modules.gui.debug.model' --- @dep modules.gui.debug.model local dump = Model.dump diff --git a/modules/gui/debug/expcore_store_view.lua b/modules/gui/debug/expcore_store_view.lua index 300acc2d..36ab8027 100644 --- a/modules/gui/debug/expcore_store_view.lua +++ b/modules/gui/debug/expcore_store_view.lua @@ -1,6 +1,6 @@ local Gui = require 'utils.gui' --- @dep utils.gui local Store = require 'expcore.store' --- @dep utils.global -local Color = require 'resources.color_presets' --- @dep resources.color_presets +local Color = require 'utils.color_presets' --- @dep utils.color_presets local Model = require 'modules.gui.debug.model' --- @dep modules.gui.debug.model local dump = Model.dump diff --git a/modules/gui/debug/global_view.lua b/modules/gui/debug/global_view.lua index df057c47..3ab51d8d 100644 --- a/modules/gui/debug/global_view.lua +++ b/modules/gui/debug/global_view.lua @@ -1,6 +1,6 @@ local Gui = require 'utils.gui' --- @dep utils.gui local Model = require 'modules.gui.debug.model' --- @dep modules.gui.debug.model -local Color = require 'resources.color_presets' --- @dep resources.color_presets +local Color = require 'utils.color_presets' --- @dep utils.color_presets local dump = Model.dump local dump_text = Model.dump_text diff --git a/modules/gui/debug/main_view.lua b/modules/gui/debug/main_view.lua index 9807329c..0771bdb1 100644 --- a/modules/gui/debug/main_view.lua +++ b/modules/gui/debug/main_view.lua @@ -1,5 +1,5 @@ local Gui = require 'utils.gui' --- @dep utils.gui -local Color = require 'resources.color_presets' --- @dep resources.color_presets +local Color = require 'utils.color_presets' --- @dep utils.color_presets local Public = {} diff --git a/modules/gui/debug/model.lua b/modules/gui/debug/model.lua index ff120941..101ba30b 100644 --- a/modules/gui/debug/model.lua +++ b/modules/gui/debug/model.lua @@ -1,5 +1,5 @@ local Gui = require 'utils.gui' --- @dep utils.gui -local table = require 'utils.table' --- @dep utils.table +local table = require 'overrides.table' --- @dep overrides.table local gui_names = Gui.names local type = type diff --git a/modules/gui/debug/package_view.lua b/modules/gui/debug/package_view.lua index f29aafbb..292bf9d7 100644 --- a/modules/gui/debug/package_view.lua +++ b/modules/gui/debug/package_view.lua @@ -1,5 +1,5 @@ local Gui = require 'utils.gui' --- @dep utils.gui -local Color = require 'resources.color_presets' --- @dep resources.color_presets +local Color = require 'utils.color_presets' --- @dep utils.color_presets local Model = require 'modules.gui.debug.model' --- @dep modules.gui.debug.model local dump_function = Model.dump_function @@ -17,9 +17,9 @@ local ignore = { math = true, debug = true, serpent = true, - ['utils.math'] = true, + ['overrides.math'] = true, util = true, - ['utils.inspect'] = true, + ['overrides.inspect'] = true, ['mod-gui'] = true } diff --git a/modules/gui/debug/redmew_global_view.lua b/modules/gui/debug/redmew_global_view.lua index a62a6151..4bff705f 100644 --- a/modules/gui/debug/redmew_global_view.lua +++ b/modules/gui/debug/redmew_global_view.lua @@ -1,7 +1,7 @@ local Gui = require 'utils.gui' --- @dep utils.gui local Global = require 'utils.global' --- @dep utils.global local Token = require 'utils.token' --- @dep utils.token -local Color = require 'resources.color_presets' --- @dep resources.color_presets +local Color = require 'utils.color_presets' --- @dep utils.color_presets local Model = require 'modules.gui.debug.model' --- @dep modules.gui.debug.model local dump = Model.dump diff --git a/modules/gui/player-list.lua b/modules/gui/player-list.lua index 0c460eb7..beecb309 100644 --- a/modules/gui/player-list.lua +++ b/modules/gui/player-list.lua @@ -9,9 +9,9 @@ local Roles = require 'expcore.roles' --- @dep expcore.roles local Store = require 'expcore.store' --- @dep expcore.store local Game = require 'utils.game' --- @dep utils.game local Event = require 'utils.event' --- @dep utils.event -local format_time = ext_require('expcore.common','format_time') --- @dep expcore.common +local format_time = _C.ext_require('expcore.common','format_time') --- @dep expcore.common local config = require 'config.action_buttons' --- @dep config.action_buttons -local Colors = require 'resources.color_presets' --- @dep resources.color_presets +local Colors = require 'utils.color_presets' --- @dep utils.color_presets -- Stores the name of the player a player has selected local selected_player_store = Store.register(function(player) diff --git a/modules/gui/rocket-info.lua b/modules/gui/rocket-info.lua index f2384a21..197699fc 100644 --- a/modules/gui/rocket-info.lua +++ b/modules/gui/rocket-info.lua @@ -8,8 +8,8 @@ local Gui = require 'expcore.gui' --- @dep expcore.gui local Roles = require 'expcore.roles' --- @dep expcore.roles local Event = require 'utils.event' --- @dep utils.event local config = require 'config.rockets' --- @dep config.rockets -local format_time = ext_require('expcore.common','format_time') --- @dep expcore.common -local Colors = require 'resources.color_presets' --- @dep resources.color_presets +local format_time = _C.ext_require('expcore.common','format_time') --- @dep expcore.common +local Colors = require 'utils.color_presets' --- @dep utils.color_presets local Rockets = require 'modules.control.rockets' --- @dep modules.control.rockets local time_formats = { diff --git a/modules/gui/science-info.lua b/modules/gui/science-info.lua index 36d4d947..9c6b794f 100644 --- a/modules/gui/science-info.lua +++ b/modules/gui/science-info.lua @@ -7,7 +7,7 @@ local Gui = require 'expcore.gui' --- @dep expcore.gui local Roles = require 'expcore.roles' --- @dep expcore.gui local Event = require 'utils.event' --- @dep utils.event -local format_time = ext_require('expcore.common','format_time') --- @dep expcore.common +local format_time = _C.ext_require('expcore.common','format_time') --- @dep expcore.common local config = require 'config.science' --- @dep config.science local Production = require 'modules.control.production' --- @dep modules.control.production diff --git a/modules/gui/task-list.lua b/modules/gui/task-list.lua index b8b260b0..702f3499 100644 --- a/modules/gui/task-list.lua +++ b/modules/gui/task-list.lua @@ -8,8 +8,8 @@ local Gui = require 'expcore.gui' --- @dep expcore.gui local Event = require 'utils.event' --- @dep utils.event local Roles = require 'expcore.roles' --- @dep expcore.roles local config = require 'config.tasks' --- @dep config.tasks -local format_time,table_keys = ext_require('expcore.common','format_time','table_keys') --- @dep expcore.common local Tasks = require 'modules.control.tasks' --- @dep modules.control.tasks +local format_time = _C.format_time --- @dep expcore.common -- Styles used for sprite buttons local Styles = { @@ -223,7 +223,7 @@ end) local function update_task(player,task_table,task_id) local task = Tasks.get_task(task_id) local task_ids = Tasks.get_force_task_ids(player.force.name) - local task_number = table.index_of(task_ids, task_id) + local task_number = table.get_index(task_ids, task_id) -- Task no longer exists so should be removed from the list if not task then @@ -240,7 +240,7 @@ local function update_task(player,task_table,task_id) -- Update the edit flow local edit_flow = task_table['edit-'..task_id] local player_allowed_edit = check_player_permissions(player,task) - local players_editing = table_keys(task.curently_editing) + local players_editing = table.get_keys(task.curently_editing) local edit_task_element = edit_flow[edit_task.name] local discard_task_element = edit_flow[discard_task.name] diff --git a/modules/gui/warp-list.lua b/modules/gui/warp-list.lua index de92d42e..52b711da 100644 --- a/modules/gui/warp-list.lua +++ b/modules/gui/warp-list.lua @@ -10,10 +10,10 @@ local Global = require 'utils.global' --- @dep utils.global local Event = require 'utils.event' --- @dep utils.event local Game = require 'utils.game' --- @dep utils.game local Roles = require 'expcore.roles' --- @dep expcore.roles -local Colors = require 'resources.color_presets' --- @dep resources.color_presets +local Colors = require 'utils.color_presets' --- @dep utils.color_presets local config = require 'config.warps' --- @dep config.warps -local format_time,table_keys = ext_require('expcore.common','format_time','table_keys') --- @dep expcore.common local Warps = require 'modules.control.warps' --- @dep modules.control.warps +local format_time = _C.format_time --- @dep expcore.common -- Stores a boolean value indexed by player name local player_in_range_store = Store.register(function(player) @@ -319,7 +319,7 @@ local function update_warp(player,warp_table,warp_id) -- Update the edit flow local edit_flow = warp_table['edit-'..warp_id] local player_allowed_edit = check_player_permissions(player,'allow_edit_warp',warp) - local players_editing = table_keys(warp.currently_editing) + local players_editing = table.get_keys(warp.currently_editing) local edit_warp_element = edit_flow[edit_warp.name] local discard_warp_element = edit_flow[discard_warp.name] diff --git a/utils/debug.lua b/overrides/debug.lua similarity index 99% rename from utils/debug.lua rename to overrides/debug.lua index 98f85a28..20be17a8 100644 --- a/utils/debug.lua +++ b/overrides/debug.lua @@ -161,4 +161,4 @@ function Debug.is_closure(func) end end -return Debug +return Debug \ No newline at end of file diff --git a/utils/inspect.lua b/overrides/inspect.lua similarity index 99% rename from utils/inspect.lua rename to overrides/inspect.lua index c13a8cd4..76605169 100644 --- a/utils/inspect.lua +++ b/overrides/inspect.lua @@ -338,5 +338,4 @@ end setmetatable(inspect, { __call = function(_, ...) return inspect.inspect(...) end }) -return inspect - +return inspect \ No newline at end of file diff --git a/utils/math.lua b/overrides/math.lua similarity index 99% rename from utils/math.lua rename to overrides/math.lua index 179005c9..a9ba046f 100644 --- a/utils/math.lua +++ b/overrides/math.lua @@ -52,4 +52,4 @@ math.degrees = function(angle) return angle * deg_to_rad end -return math +return math \ No newline at end of file diff --git a/utils/print_override.lua b/overrides/print.lua similarity index 69% rename from utils/print_override.lua rename to overrides/print.lua index 848c91b2..22f3c72a 100644 --- a/utils/print_override.lua +++ b/overrides/print.lua @@ -1,5 +1,4 @@ -local Public = {} - +--luacheck:ignore global print local locale_string = {'', '[PRINT] ', nil} local raw_print = print @@ -8,6 +7,4 @@ function print(str) log(locale_string) end -Public.raw_print = raw_print - -return Public +return raw_print \ No newline at end of file diff --git a/utils/require_override.lua b/overrides/require.lua similarity index 75% rename from utils/require_override.lua rename to overrides/require.lua index 06779e59..36430248 100644 --- a/utils/require_override.lua +++ b/overrides/require.lua @@ -1,4 +1,5 @@ -local loaded = _G.package.loaded +--luacheck:ignore global require +local loaded = package.loaded local raw_require = require function require(path) diff --git a/resources/data_stages.lua b/overrides/stages.lua similarity index 91% rename from resources/data_stages.lua rename to overrides/stages.lua index 516fb321..8a7fb800 100644 --- a/resources/data_stages.lua +++ b/overrides/stages.lua @@ -10,3 +10,5 @@ _STAGE = { --config_change = 7, runtime = 8 } + +_LIFECYCLE = _STAGE.control \ No newline at end of file diff --git a/utils/table.lua b/overrides/table.lua similarity index 55% rename from utils/table.lua rename to overrides/table.lua index 4b1973e2..e3823302 100644 --- a/utils/table.lua +++ b/overrides/table.lua @@ -22,7 +22,7 @@ end -- The catch is that fast_remove doesn't guarantee to maintain the order of items in the array. -- @param tbl arrayed table -- @param index Must be >= 0. The case where index > #tbl is handled. -function table.fast_remove(tbl, index) +function table.remove_index(tbl, index) local count = #tbl if index > count then return @@ -36,7 +36,7 @@ end --- Adds the contents of table t2 to table t1 -- @param t1
to insert into -- @param t2
to insert from -function table.add_all(t1, t2) +function table.merge_table(t1, t2) for k, v in pairs(t2) do if tonumber(k) then t1[#t1 + 1] = v @@ -46,11 +46,74 @@ function table.add_all(t1, t2) end end +--[[-- Much faster method for inserting items into an array +@tparam table tbl the table that will have the values added to it +@tparam[opt] number start_index the index at which values will be added, nil means end of the array +@tparam table values the new values that will be added to the table +@treturn table the table that was passed as the first argument +@usage-- Adding 1000 values into the middle of the array +local tbl = {} +local values = {} +for i = 1,1000 do tbl[i] = i values[i] = i end +table.array_insert(tbl,500,values) -- around 0.4ms +]] +function table.array_insert(tbl,start_index,values) + if not values then + values = start_index + start_index = nil + end + + if start_index then + local starting_length = #tbl + local adding_length = #values + local move_to = start_index+adding_length+1 + for offset = starting_length-start_index, 0, -1 do + tbl[move_to+offset] = tbl[starting_length+offset] + end + start_index = start_index-1 + else + start_index = #tbl + end + + for offset, item in ipairs(values) do + tbl[start_index+offset] = item + end + + return tbl +end + +--[[-- Much faster method for inserting keys into a table +@tparam table tbl the table that will have keys added to it +@tparam[opt] number start_index the index at which values will be added, nil means end of the array, numbered indexs only +@tparam table tbl2 the table that may contain both string and numbered keys +@treturn table the table passed as the first argument +@usage-- Merging two tables +local tbl = {} +local tbl2 = {} +for i = 1,100 do tbl[i] = i tbl['_'..i] = i tbl2[i] = i tbl2['__'..i] = i end +table.table_insert(tbl,50,tbl2) +]] +function table.table_insert(tbl,start_index,tbl2) + if not tbl2 then + tbl2 = start_index + start_index = nil + end + + table.array_insert(tbl,start_index,tbl2) + for key, value in pairs(tbl2) do + if not tonumber(key) then + tbl[key] = value + end + end + + return tbl +end + --- Checks if a table contains an element -- @param t
-- @param e table element -- @return the index of the element or nil -function table.index_of(t, e) +function table.get_key(t, e) for k, v in pairs(t) do if v == e then return k @@ -63,7 +126,7 @@ end -- @param t
-- @param e table element -- @return the index of the element or nil -function table.index_of_in_array(t, e) +function table.get_index(t, e) for i = 1, #t do if t[i] == e then return i @@ -72,22 +135,33 @@ function table.index_of_in_array(t, e) return nil end -local index_of = table.index_of --- Checks if a table contains an element -- @param t
-- @param e table element -- @return indicating success function table.contains(t, e) - return index_of(t, e) and true or false + return table.get_key(t, e) and true or false end -local index_of_in_array = table.index_of_in_array --- Checks if the arrayed portion of a table contains an element -- @param t
-- @param e table element -- @return indicating success function table.array_contains(t, e) - return index_of_in_array(t, e) and true or false + return table.get_index(t, e) and true or false +end + +--- Extracts certain keys from a table +-- @usage local key_three, key_one = extract({key_one='foo',key_two='bar',key_three=true},'key_three','key_one') +-- @tparam table tbl table the which contains the keys +-- @tparam string ... the names of the keys you want extracted +-- @return the keys in the order given +function table.extract_keys(tbl,...) + local values = {} + for _,key in pairs({...}) do + table.insert(values,tbl[key]) + end + return unpack(values) end --- Adds an element into a specific index position while shuffling the rest down @@ -151,6 +225,21 @@ function table.get_random_weighted(weighted_table, item_index, weight_index) end end +--- Clears all existing entries in a table +-- @param t
to clear +-- @param array to indicate whether the table is an array or not +function table.clear_table(t, array) + if array then + for i = 1, #t do + t[i] = nil + end + else + for i in pairs(t) do + t[i] = nil + end + end +end + --- Creates a fisher-yates shuffle of a sequential number-indexed table -- because this uses math.random, it cannot be used outside of events if no rng is supplied -- from: http://www.sdknews.com/cross-platform/corona/tutorial-how-to-shuffle-table-items @@ -171,19 +260,102 @@ function table.shuffle_table(t, rng) end end ---- Clears all existing entries in a table --- @param t
to clear --- @param array to indicate whether the table is an array or not -function table.clear_table(t, array) - if array then - for i = 1, #t do - t[i] = nil +--- Default table comparator sort function. +-- @local +-- @param x one comparator operand +-- @param y the other comparator operand +-- @return true if x logically comes before y in a list, false otherwise +local function sortFunc(x, y) --sorts tables with mixed index types. + local tx = type(x) + local ty = type(y) + if tx == ty then + if type(x) == 'string' then + return string.lower(x) < string.lower(y) + else + return x < y + end + elseif tx == 'number' then + return true --only x is a number and goes first + else + return false --only y is a number and goes first + end +end + +--- Returns a copy of all of the values in the table. +-- @tparam table tbl the to copy the keys from, or an empty table if tbl is nil +-- @tparam[opt] boolean sorted whether to sort the keys (slower) or keep the random order from pairs() +-- @tparam[opt] boolean as_string whether to try and parse the values as strings, or leave them as their existing type +-- @treturn array an array with a copy of all the values in the table +function table.get_values(tbl, sorted, as_string) + if not tbl then return {} end + local valueset = {} + local n = 0 + if as_string then --checking as_string /before/ looping is faster + for _, v in pairs(tbl) do + n = n + 1 + valueset[n] = tostring(v) end else - for i in pairs(t) do - t[i] = nil + for _, v in pairs(tbl) do + n = n + 1 + valueset[n] = v end end + if sorted then + table.sort(valueset,sortFunc) + end + return valueset +end + +--- Returns a copy of all of the keys in the table. +-- @tparam table tbl the to copy the keys from, or an empty table if tbl is nil +-- @tparam[opt] boolean sorted whether to sort the keys (slower) or keep the random order from pairs() +-- @tparam[opt] boolean as_string whether to try and parse the keys as strings, or leave them as their existing type +-- @treturn array an array with a copy of all the keys in the table +function table.get_keys(tbl, sorted, as_string) + if not tbl then return {} end + local keyset = {} + local n = 0 + if as_string then --checking as_string /before/ looping is faster + for k, _ in pairs(tbl) do + n = n + 1 + keyset[n] = tostring(k) + end + else + for k, _ in pairs(tbl) do + n = n + 1 + keyset[n] = k + end + end + if sorted then + table.sort(keyset,sortFunc) + end + return keyset +end + +--- Returns the list is a sorted way that would be expected by people (this is by key) +-- @tparam table tbl the table to be sorted +-- @treturn table the sorted table +function table.alphanumsort(tbl) + local o = table.get_keys(tbl) + local function padnum(d) local dec, n = string.match(d, "(%.?)0*(.+)") + return #dec > 0 and ("%.12f"):format(d) or ("%s%03d%s"):format(dec, #n, n) end + table.sort(o, function(a,b) + return tostring(a):gsub("%.?%d+",padnum)..("%3d"):format(#b) + < tostring(b):gsub("%.?%d+",padnum)..("%3d"):format(#a) end) + local _tbl = {} + for _,k in pairs(o) do _tbl[k] = tbl[k] end + return _tbl +end + +--- Returns the list is a sorted way that would be expected by people (this is by key) (faster alternative than above) +-- @tparam table tbl the table to be sorted +-- @treturn table the sorted table +function table.keysort(tbl) + local o = table.get_keys(tbl,true) + local _tbl = {} + for _,k in pairs(o) do _tbl[k] = tbl[k] end + return _tbl end --[[ @@ -238,7 +410,7 @@ require 'util' -- process is a function which allow altering the passed object before transforming it into a string. -- A typical way to use it would be to remove certain values so that they don't appear at all. -- return the prettied table -table.inspect = require 'utils.inspect' --- @dep utils.inspect +table.inspect = require 'overrides.inspect' --- @dep overrides.inspect --- Takes a table and returns the number of entries in the table. (Slower than #table, faster than iterating via pairs) table.size = table_size @@ -262,4 +434,4 @@ table.merge = util.merge -- @return table.equals = table.compare -return table +return table \ No newline at end of file diff --git a/resources/version.lua b/resources/version.lua deleted file mode 100644 index 98d7ac58..00000000 --- a/resources/version.lua +++ /dev/null @@ -1,2 +0,0 @@ -global.redmew_version = nil -global.expgaming_version = '5.0.0' \ No newline at end of file diff --git a/utils/alien_evolution_progress.lua b/utils/alien_evolution_progress.lua deleted file mode 100644 index 03c97aa0..00000000 --- a/utils/alien_evolution_progress.lua +++ /dev/null @@ -1,179 +0,0 @@ ---[[-- info - Original (javascript) version: https://hastebin.com/udakacavap.js - Can be tested against: https://wiki.factorio.com/Enemies#Spawn_chances_by_evolution_factor -]] - --- dependencies -local Global = require 'utils.global' --- @dep utils.global -local Debug = require 'utils.debug' --- @dep utils.debug -local table = require 'utils.table' --- @dep utils.table - --- localized functions -local get_random_weighted = table.get_random_weighted -local round = math.round -local ceil = math.ceil -local floor = math.floor -local random = math.random -local pairs = pairs -local format = string.format - --- this -local AlienEvolutionProgress = {} - -local memory = { - spawner_specifications = {}, - spawner_specifications_count = 0, - evolution_cache = { - ['biter-spawner'] = { - evolution = -1, - weight_table = {}, - }, - ['spitters-spawner'] = { - evolution = -1, - weight_table = {}, - }, - }, -} - -Global.register_init({ - memory = memory, -}, function(tbl) - for name, prototype in pairs(game.entity_prototypes) do - if prototype.type == 'unit-spawner' and prototype.subgroup.name == 'enemies' then - tbl.memory.spawner_specifications[name] = prototype.result_units - memory.spawner_specifications_count = memory.spawner_specifications_count + 1 - end - end -end, function(tbl) - memory = tbl.memory -end) - -local function lerp(low, high, pos) - local s = high.evolution_factor - low.evolution_factor; - local l = (pos - low.evolution_factor) / s; - return (low.weight * (1 - l)) + (high.weight * l) -end - -local function get_values(map, evolution_factor) - local result = {} - local sum = 0 - - for _, spawner_data in pairs(map) do - local list = spawner_data.spawn_points; - local low = list[1]; - local high = list[#list]; - - for _, val in pairs(list) do - local val_evolution = val.evolution_factor - if val_evolution <= evolution_factor and val_evolution > low.evolution_factor then - low = val; - end - if val_evolution >= evolution_factor and val_evolution < high.evolution_factor then - high = val - end - end - - local val - if evolution_factor <= low.evolution_factor then - val = low.weight - elseif evolution_factor >= high.evolution_factor then - val = high.weight; - else - val = lerp(low, high, evolution_factor) - end - sum = sum + val; - - result[spawner_data.unit] = val; - end - - local weighted_table = {} - local count = 0 - for index, _ in pairs(result) do - count = count + 1 - weighted_table[count] = {index, result[index] / sum} - end - - return weighted_table; -end - -local function get_spawner_values(spawner, evolution) - local spawner_specification = memory.spawner_specifications[spawner] - if not spawner_specification then - Debug.print(format('Spawner "%s" does not exist in the prototype data', spawner)) - return - end - - local cache = memory.evolution_cache[spawner] - - if not cache then - cache = { - evolution = -1, - weight_table = {}, - } - memory.evolution_cache[spawner] = cache - end - - local evolution_value = round(evolution * 100) - if (cache.evolution < evolution_value) then - cache.evolution = evolution_value - cache.weight_table = get_values(spawner_specification, evolution) - end - - return cache.weight_table -end - -local function calculate_total(count, spawner, evolution) - if count == 0 then - return {} - end - - local spawner_values = get_spawner_values(spawner, evolution) - if not spawner_values then - return {} - end - - local aliens = {} - for _ = 1, count do - local name = get_random_weighted(spawner_values) - aliens[name] = (aliens[name] or 0) + 1 - end - - return aliens -end - ----Creates the spawner_request structure required for AlienEvolutionProgress.get_aliens for all ----available spawner's. If dividing the total spawner's by the total aliens causes a fraction, the ----fraction will decide a chance to spawn. 1 alien for 2 spawner's will have 50% on both. ----@param total_aliens table -function AlienEvolutionProgress.create_spawner_request(total_aliens) - local per_spawner = total_aliens / memory.spawner_specifications_count - local fraction = per_spawner % 1 - - local spawner_request = {} - for spawner, _ in pairs(memory.spawner_specifications) do - local count = per_spawner - if fraction > 0 then - if random() > fraction then - count = ceil(count) - else - count = floor(count) - end - end - spawner_request[spawner] = count - end - - return spawner_request -end - -function AlienEvolutionProgress.get_aliens(spawner_requests, evolution) - local aliens = {} - for spawner, count in pairs(spawner_requests) do - for name, amount in pairs(calculate_total(count, spawner, evolution)) do - aliens[name] = (aliens[name] or 0) + amount - end - end - - return aliens -end - -return AlienEvolutionProgress diff --git a/resources/color_presets.lua b/utils/color_presets.lua similarity index 100% rename from resources/color_presets.lua rename to utils/color_presets.lua diff --git a/utils/command.lua b/utils/command.lua deleted file mode 100644 index 692eb285..00000000 --- a/utils/command.lua +++ /dev/null @@ -1,326 +0,0 @@ -local Event = require 'utils.event' --- @dep utils.event -local Game = require 'utils.game' --- @dep utils.game -local Utils = require 'utils.core' --- @dep utils.core -local Timestamp = require 'utils.timestamp' --- @dep utils.timestamp -local Rank = require 'features.rank_system' --- @dep features.rank_system -local Donator = require 'features.donator' --- @dep features.donator -local Server = require 'features.server' --- @dep features.server -local Ranks = require 'resources.ranks' --- @dep resources.ranks - -local insert = table.insert -local format = string.format -local next = next -local serialize = serpent.line -local match = string.match -local gmatch = string.gmatch -local get_rank_name = Rank.get_rank_name - -local Command = {} - -local deprecated_command_alternatives = { - ['silent-command'] = 'sc', - ['tpplayer'] = 'tp ', - ['tppos'] = 'tp', - ['tpmode'] = 'tp mode', - ['color-redmew'] = 'redmew-color' -} - -local notify_on_commands = { - ['version'] = 'RedMew has a version as well, accessible via /redmew-version', - ['color'] = 'RedMew allows color saving and a color randomiser: check out /redmew-color', - ['ban'] = 'In case your forgot: please remember to include a message on how to appeal a ban' -} - -local option_names = { - ['description'] = 'A description of the command', - ['arguments'] = 'A table of arguments, example: {"foo", "bar"} would map the first 2 arguments to foo and bar', - ['default_values'] = 'A default value for a given argument when omitted, example: {bar = false}', - ['required_rank'] = 'Set this to determines what rank is required to execute a command', - ['donator_only'] = 'Set this to true if only donators may execute this command', - ['debug_only'] = 'Set this to true if it should be registered when _DEBUG is true', - ['cheat_only'] = 'Set this to true if it should be registered when _CHEATS is true', - ['allowed_by_server'] = 'Set to true if the server (host) may execute this command', - ['allowed_by_player'] = 'Set to false to disable players from executing this command', - ['log_command'] = 'Set to true to log commands. Always true when admin is required', - ['capture_excess_arguments'] = 'Allows the last argument to be the remaining text in the command', - ['custom_help_text'] = 'Sets a custom help text to override the auto-generated help', -} - ----Validates if there aren't any wrong fields in the options. ----@param command_name string ----@param options table -local function assert_existing_options(command_name, options) - local invalid = {} - for name, _ in pairs(options) do - if not option_names[name] then - insert(invalid, name) - end - end - - if next(invalid) then - error(format("The following options were given to the command '%s' but are invalid: %s", command_name, serialize(invalid))) - end -end - ----Adds a command to be executed. ---- ----Options table accepts the following structure: { ---- description = 'A description of the command', ---- arguments = {'foo', 'bar'}, -- maps arguments to these names in the given sequence ---- default_values = {bar = false}, -- gives a default value to 'bar' when omitted ---- required_rank = Ranks.regular, -- defaults to Ranks.guest ---- donator_only = true, -- defaults to false ---- debug_only = true, -- registers the command if _DEBUG is set to true, defaults to false ---- cheat_only = true, -- registers the command if _CHEATS is set to true, defaults to false ---- allowed_by_server = true, -- lets the server execute this, defaults to false ---- allowed_by_player = false, -- lets players execute this, defaults to true ---- log_command = true, -- defaults to false unless admin only, then always true ---- capture_excess_arguments = true, -- defaults to false, captures excess arguments in the last argument, useful for sentences ----} ---- ----The callback receives the following arguments: ---- - arguments (indexed by name, value is extracted from the parameters) ---- - the LuaPlayer or nil if it doesn't exist (such as the server player) ---- - the game tick in which the command was executed ---- ----@param command_name string ----@param options table ----@param callback function -function Command.add(command_name, options, callback) - local description = options.description or '[Undocumented command]' - local arguments = options.arguments or {} - local default_values = options.default_values or {} - local required_rank = options.required_rank or Ranks.guest - local donator_only = options.donator_only or false - local debug_only = options.debug_only or false - local cheat_only = options.cheat_only or false - local capture_excess_arguments = options.capture_excess_arguments or false - local custom_help_text = options.custom_help_text or false - local allowed_by_server = options.allowed_by_server or false - local allowed_by_player = options.allowed_by_player - local log_command = options.log_command or (required_rank >= Ranks.admin) or false - local argument_list_size = table_size(arguments) - local argument_list = '' - - assert_existing_options(command_name, options) - - if nil == options.allowed_by_player then - allowed_by_player = true - end - - if (not _DEBUG and debug_only) and (not _CHEATS and cheat_only) then - return - end - - if not allowed_by_player and not allowed_by_server then - error(format("The command '%s' is not allowed by the server nor player, please enable at least one of them.", command_name)) - end - - for index, argument_name in pairs(arguments) do - local argument_display = argument_name - for default_value_name, _ in pairs(default_values) do - if default_value_name == argument_name then - argument_display = argument_display .. ':optional' - break - end - end - - if argument_list_size == index and capture_excess_arguments then - argument_display = argument_display .. ':sentence' - end - - argument_list = format('%s<%s> ', argument_list, argument_display) - end - - local extra = '' - - if allowed_by_server and not allowed_by_player then - extra = ' (Server only)' - elseif allowed_by_player and (required_rank > Ranks.guest) then - extra = {'command.required_rank', get_rank_name(required_rank)} - elseif allowed_by_player and donator_only then - extra = ' (Donator only)' - end - - local help_text = {'command.help_text_format',(custom_help_text or argument_list), description, extra} - - commands.add_command(command_name, help_text, function (command) - local print -- custom print reference in case no player is present - local player = game.player - local player_name = player and player.valid and player.name or '' - if not player or not player.valid then - print = log - - if not allowed_by_server then - print(format("The command '%s' is not allowed to be executed by the server.", command_name)) - return - end - else - print = player.print - - if not allowed_by_player then - print(format("The command '%s' is not allowed to be executed by players.", command_name)) - return - end - - if Rank.less_than(player_name, required_rank) then - print({'command.higher_rank_needed', command_name, get_rank_name(required_rank)}) - return - end - - if donator_only and not Donator.is_donator(player_name) then - print(format("The command '%s' is only allowed for donators.", command_name)) - return - end - end - - local named_arguments = {} - local from_command = {} - local raw_parameter_index = 1 - for param in gmatch(command.parameter or '', '%S+') do - if capture_excess_arguments and raw_parameter_index == argument_list_size then - if not from_command[raw_parameter_index] then - from_command[raw_parameter_index] = param - else - from_command[raw_parameter_index] = from_command[raw_parameter_index] .. ' ' .. param - end - else - from_command[raw_parameter_index] = param - raw_parameter_index = raw_parameter_index + 1 - end - end - - local errors = {} - - for index, argument in pairs(arguments) do - local parameter = from_command[index] - - if not parameter then - for default_value_name, default_value in pairs(default_values) do - if default_value_name == argument then - parameter = default_value - break - end - end - end - - if parameter == nil then - insert(errors, format('Argument "%s" from command %s is missing.', argument, command_name)) - else - named_arguments[argument] = parameter - end - end - - local return_early = false - - for _, error in pairs(errors) do - return_early = true - print(error) - end - - if return_early then - return - end - - if log_command then - local tick = 'pre-game' - if game then - tick = Utils.format_time(game.tick) - end - local server_time = Server.get_current_time() - if server_time then - server_time = format('(Server time: %s)', Timestamp.to_string(server_time)) - else - server_time = '' - end - - log(format('%s(Map time: %s) [%s Command] %s, used: %s %s', server_time, tick, (options.required_rank >= Ranks.admin) and 'Admin' or 'Player', player_name, command_name, serialize(named_arguments))) - end - - local success, error = pcall(function () - callback(named_arguments, player, command.tick) - end) - - if not success then - local serialized_arguments = serialize(named_arguments) - if _DEBUG then - print(format("%s triggered an error running a command and has been logged: '%s' with arguments %s", player_name, command_name, serialized_arguments)) - print(error) - return - end - - print(format('There was an error running %s, it has been logged.', command_name)) - log(format("Error while running '%s' with arguments %s: %s", command_name, serialized_arguments, error)) - end - end) -end - -function Command.search(keyword) - local matches = {} - local count = 0 - keyword = keyword:lower() - for name, description in pairs(commands.commands) do - local command = format('%s %s', name, description) - if match(command:lower(), keyword) then - count = count + 1 - matches[count] = command - end - end - - -- built-in commands use LocalisedString, which cannot be translated until player.print is called - for name in pairs(commands.game_commands) do - name = name - if match(name:lower(), keyword) then - count = count + 1 - matches[count] = name - end - end - - return matches -end - ---- Trigger messages on deprecated or defined commands, ignores the server -local function on_command(event) - if not event.player_index then - return - end - - local alternative = deprecated_command_alternatives[event.command] - if alternative then - local player = Game.get_player_by_index(event.player_index) - if player then - player.print(format('Warning! Usage of the command "/%s" is deprecated. Please use "/%s" instead.', event.command, alternative)) - end - end - - local notification = notify_on_commands[event.command] - if notification and event.player_index then - local player = Game.get_player_by_index(event.player_index) - if player then - player.print(notification) - end - end -end - ---- Traps command errors if not in DEBUG. -if not _DEBUG then - local old_add_command = commands.add_command - commands.add_command = - function(name, desc, func) - old_add_command( - name, - desc, - function(cmd) - local success, error = pcall(func, cmd) - if not success then - log(error) - Game.player_print('Sorry there was an error running ' .. cmd.name) - end - end - ) - end -end - -Event.add(defines.events.on_console_command, on_command) - -return Command diff --git a/utils/core.lua b/utils/core.lua deleted file mode 100644 index 744265b7..00000000 --- a/utils/core.lua +++ /dev/null @@ -1,223 +0,0 @@ ---- This file contains core utilities used by the redmew scenario. - --- Dependencies -local Game = require 'utils.game' --- @dep utils.game -local Color = require 'resources.color_presets' --- @dep resources.color_presets - --- localized functions -local random = math.random -local sqrt = math.sqrt -local floor = math.floor -local match = string.match -local insert = table.insert -local concat = table.concat - --- local constants -local prefix = '## - ' -local minutes_to_ticks = 60 * 60 -local hours_to_ticks = 60 * 60 * 60 -local ticks_to_minutes = 1 / minutes_to_ticks -local ticks_to_hours = 1 / hours_to_ticks - --- local variables -local Module = {} - ---- Measures distance between pos1 and pos2 -function Module.distance(pos1, pos2) - local dx = pos2.x - pos1.x - local dy = pos2.y - pos1.y - return sqrt(dx * dx + dy * dy) -end - ---- Takes msg and prints it to all players except provided player --- @param msg table if locale is used --- @param player the player not to send the message to --- @param color
the color to use for the message, defaults to white -function Module.print_except(msg, player, color) - if not color then - color = Color.white - end - - for _, p in pairs(game.connected_players) do - if p ~= player then - p.print(msg, color) - end - end -end - ---- Prints a message to all online admins --- @param msg table if locale is used --- @param source string must be the name of a player, nil for server. -function Module.print_admins(msg, source) - local source_name - local chat_color - if source then - if type(source) == 'string' then - source_name = source - chat_color = game.players[source].chat_color - else - source_name = source.name - chat_color = source.chat_color - end - else - source_name = 'Server' - chat_color = Color.yellow - end - local formatted_msg = {'utils_core.print_admins',prefix, source_name, msg} - log(formatted_msg) - for _, p in pairs(game.connected_players) do - if p.admin then - p.print(formatted_msg, chat_color) - end - end -end - ---- Returns a valid string with the name of the actor of a command. -function Module.get_actor() - if game.player then - return game.player.name - end - return '' -end - -function Module.cast_bool(var) - if var then - return true - else - return false - end -end - -function Module.find_entities_by_last_user(player, surface, filters) - if type(player) == 'string' or not player then - error("bad argument #1 to '" .. debug.getinfo(1, 'n').name .. "' (number or LuaPlayer expected, got " .. type(player) .. ')', 1) - return - end - if type(surface) ~= 'table' and type(surface) ~= 'number' then - error("bad argument #2 to '" .. debug.getinfo(1, 'n').name .. "' (number or LuaSurface expected, got " .. type(surface) .. ')', 1) - return - end - local entities = {} - local filter = filters or {} - if type(surface) == 'number' then - surface = game.surfaces[surface] - end - if type(player) == 'number' then - player = Game.get_player_by_index(player) - end - filter.force = player.force.name - for _, e in pairs(surface.find_entities_filtered(filter)) do - if e.last_user == player then - insert(entities, e) - end - end - return entities -end - -function Module.ternary(c, t, f) - if c then - return t - else - return f - end -end - ---- Takes a time in ticks and returns a string with the time in format "x hour(s) x minute(s)" -function Module.format_time(ticks) - local result = {} - - local hours = floor(ticks * ticks_to_hours) - if hours > 0 then - ticks = ticks - hours * hours_to_ticks - insert(result, hours) - if hours == 1 then - insert(result, 'hour') - else - insert(result, 'hours') - end - end - - local minutes = floor(ticks * ticks_to_minutes) - insert(result, minutes) - if minutes == 1 then - insert(result, 'minute') - else - insert(result, 'minutes') - end - - return concat(result, ' ') -end - ---- Prints a message letting the player know they cannot run a command --- @param name string name of the command -function Module.cant_run(name) - Game.player_print("Can't run command (" .. name .. ') - insufficient permission.') -end - ---- Logs the use of a command and its user --- @param actor string with the actor's name (usually acquired by calling get_actor) --- @param command the command's name as table element --- @param parameters the command's parameters as a table (optional) -function Module.log_command(actor, command, parameters) - local action = concat {'[Admin-Command] ', actor, ' used: ', command} - if parameters then - action = concat {action, ' ', parameters} - end - log(action) -end - -function Module.comma_value(n) -- credit http://richard.warburton.it - local left, num, right = match(n, '^([^%d]*%d)(%d*)(.-)$') - return left .. (num:reverse():gsub('(%d%d%d)', '%1,'):reverse()) .. right -end - ---- Asserts the argument is one of type arg_types --- @param arg the variable to check --- @param arg_types the type as a table of sings --- @return boolean -function Module.verify_mult_types(arg, arg_types) - for _, arg_type in pairs(arg_types) do - if type(arg) == arg_type then - return true - end - end - return false -end - ---- Returns a random RGB color as a table -function Module.random_RGB() - return {r = random(0, 255), g = random(0, 255), b = random(0, 255)} -end - ---- Sets a table element to value while also returning value. --- @param tbl table to change the element of --- @param key string --- @param value nil|boolean|number|string|table to set the element to --- @return value -function Module.set_and_return(tbl, key, value) - tbl[key] = value - return value -end - --- add utility functions that exist in base factorio/util -require 'util' - ---- Moves a position according to the parameters given --- Notice: only accepts cardinal directions as direction --- @param position
table containing a map position --- @param direction north, east, south, west --- @param distance --- @return
modified position -Module.move_position = util.moveposition - ---- Takes a direction and gives you the opposite --- @param direction north, east, south, west, northeast, northwest, southeast, southwest --- @return representing the direction -Module.opposite_direction = util.oppositedirection - ---- Takes the string of a module and returns whether is it available or not --- @param name the name of the module (ex. 'utils.core') --- @return -Module.is_module_available = util.ismoduleavailable - -return Module diff --git a/utils/dump_env.lua b/utils/dump_env.lua deleted file mode 100644 index 97f92ff0..00000000 --- a/utils/dump_env.lua +++ /dev/null @@ -1,32 +0,0 @@ ---- A small debugging tool that writes the contents of _ENV to a file when the game loads. --- Useful for ensuring you get the same information when loading --- the reference and desync levels in desync reports. --- dependencies -local table = require 'utils.table' --- @dep utils.table -local Event = require 'utils.event' --- @dep utils.event - --- localized functions -local inspect = table.inspect - --- local constants -local filename = 'env_dump.lua' - --- Removes metatables and the package table -local filter = function(item, path) - if path[#path] ~= inspect.METATABLE and item ~= 'package' then - return item - end -end - -local function player_joined(event) - local dump_string = inspect(_ENV, {process = filter}) - if dump_string then - local s = string.format('tick on join: %s\n%s', event.tick, dump_string) - game.write_file(filename, s) - game.print('_ENV dumped into ' .. filename) - else - game.print('_ENV not dumped, dump_string was nil') - end -end - -Event.add(defines.events.on_player_joined_game, player_joined) diff --git a/utils/event.lua b/utils/event.lua index d4d3bd85..09673c5d 100644 --- a/utils/event.lua +++ b/utils/event.lua @@ -97,7 +97,7 @@ local EventCore = require 'utils.event_core' --- @dep utils.event_core local Global = require 'utils.global' --- @dep utils.global local Token = require 'utils.token' --- @dep utils.token -local Debug = require 'utils.debug' --- @dep utils.debug +local Debug = require 'overrides.debug' --- @dep overrides.debug local table_remove = table.remove local core_add = EventCore.add diff --git a/utils/game.lua b/utils/game.lua index 946d2420..c5ff5db2 100644 --- a/utils/game.lua +++ b/utils/game.lua @@ -1,5 +1,5 @@ local Global = require 'utils.global' --- @dep utils.global -local Color = require 'resources.color_presets' --- @dep resources.color_presets +local Color = require 'utils.color_presets' --- @dep utils.color_presets local pairs = pairs local Game = {} diff --git a/utils/player_rewards.lua b/utils/player_rewards.lua deleted file mode 100644 index dec49ae7..00000000 --- a/utils/player_rewards.lua +++ /dev/null @@ -1,154 +0,0 @@ -local Global = require 'utils.global' --- @dep utils.global -local Game = require 'utils.game' --- @dep utils.game -local PlayerStats = require 'features.player_stats' --- @dep features.player_stats -local Command = require 'utils.command' --- @dep utils.command -local Ranks = require 'resources.ranks' --- @dep resources.ranks - -local format = string.format -local abs = math.abs -local concat = table.concat - -local Public = {} -local reward_token = {global.config.player_rewards.token} or {global.config.market.currency} or {'coin'} - -Global.register( - { - reward_token = reward_token - }, - function(tbl) - reward_token = tbl.reward_token - end -) - ---- Returns the single or plural form of the token name -local function get_token_plural(quantity) - if quantity and quantity > 1 then - return concat({reward_token[1], 's'}) - else - return reward_token[1] - end -end - ---- Set the item to use for rewards --- @param reward string - item name to use as reward --- @return boolean true - indicating success -Public.set_reward = function(reward) - if global.config.player_rewards.enabled == false then - return false - end - - reward_token[1] = reward - return true -end - ---- Returns the name of the reward item -Public.get_reward = function() - return reward_token[1] -end - ---- Gives reward tokens to the player --- @param player --- @param amount of reward tokens --- @param message an optional message to send to the affected player --- @return indicating how many were inserted or if operation failed -Public.give_reward = function(player, amount, message) - if global.config.player_rewards.enabled == false then - return 0 - end - - local player_index - if type(player) == 'number' then - player_index = player - player = Game.get_player_by_index(player) - else - player_index = player.index - end - local reward = {name = reward_token[1], count = amount} - if not player.can_insert(reward) then - return 0 - end - if message then - player.print(message) - end - local coin_difference = player.insert(reward) - if reward_token[1] == 'coin' then - PlayerStats.change_coin_earned(player_index, coin_difference) - end - return coin_difference -end - ---- Removes reward tokens from the player --- @param player --- @param amount of reward tokens --- @param message an optional message to send to the affected player --- @return indicating how many were removed or if operation failed -Public.remove_reward = function(player, amount, message) - if global.config.player_rewards.enabled == false then - return 0 - end - - local player_index - if type(player) == 'number' then - player_index = player - player = Game.get_player_by_index(player) - else - player_index = player.index - end - local unreward = {name = reward_token[1], count = amount} - if message then - player.print(message) - end - local coin_difference = player.remove_item(unreward) - if reward_token[1] == 'coin' then - PlayerStats.change_coin_earned(player_index, -coin_difference) - end - return coin_difference -end - -Command.add( - 'reward', - { - description = 'Gives a reward to a target player (removes if quantity is negative)', - arguments = {'target', 'quantity', 'reason'}, - default_values = {reason = false}, - required_rank = Ranks.admin, - capture_excess_arguments = true, - allowed_by_server = true, - allowed_by_player = true - }, - function(args, player) - local player_name = 'server' - if player then - player_name = player.name - end - - local target_name = args.target - local target = game.players[target_name] - if not target then - player.print('Target not found.') - return - end - - local quantity = tonumber(args.quantity) - if quantity > 0 then - Public.give_reward(target, quantity) - local string = format('%s has rewarded %s with %s %s', player_name, target_name, quantity, get_token_plural(quantity)) - if args.reason then - string = format('%s for %s', string, args.reason) - end - game.print(string) - elseif quantity < 0 then - quantity = abs(quantity) - Public.remove_reward(target, quantity) - local string = format('%s has punished %s by taking %s %s', player_name, target_name, quantity, get_token_plural(quantity)) - if args.reason then - string = format('%s for %s', string, args.reason) - end - game.print(string) - else - Game.player_print(" A reward of 0 is neither a reward nor a punishment, it's just dumb. Try harder.") - end - end -) - -return Public diff --git a/utils/recipe_locker.lua b/utils/recipe_locker.lua deleted file mode 100644 index 53d6c59c..00000000 --- a/utils/recipe_locker.lua +++ /dev/null @@ -1,58 +0,0 @@ ---- A module to prevent recipes from being unlocked by research. Accessed via the public functions. -local Event = require 'utils.event' --- @dep utils.event -local Global = require 'utils.global' --- @dep utils.global - -local Public = {} - -local recipes = {} - -Global.register( - { - recipes = recipes - }, - function(tbl) - recipes = tbl.recipes - end -) - -Event.add( - defines.events.on_research_finished, - function(event) - local p_force = game.forces.player - local r = event.research - for _, effect in pairs(r.effects) do - local recipe = effect.recipe - if recipe and recipes[recipe] then - p_force.recipes[recipe].enabled = false - end - end - end -) - -Event.on_init( - function() - for recipe in pairs(recipes) do - game.forces.player.recipes[recipe].enabled = false - end - end -) - ---- Locks recipes, preventing them from being enabled by research. --- Does not check if they should be enabled/disabled by existing research. --- @param tbl
an array of recipe strings -function Public.lock_recipes(tbl) - for i = 1, #tbl do - recipes[tbl[i]] = true - end -end - ---- Unlocks recipes, allowing them to be enabled by research. --- Does not check if they should be enabled/disabled by existing research. --- @param tbl
an array of recipe strings -function Public.unlock_recipes(tbl) - for i = 1, #tbl do - recipes[tbl[i]] = nil - end -end - -return Public diff --git a/utils/redmew_settings.lua b/utils/redmew_settings.lua deleted file mode 100644 index 2e4b0404..00000000 --- a/utils/redmew_settings.lua +++ /dev/null @@ -1,178 +0,0 @@ -local Global = require 'utils.global' --- @dep utils.global -local type = type -local error = error -local tonumber = tonumber -local tostring = tostring -local pairs = pairs -local format = string.format - ---- Contains a set of callable that will attempt to sanitize and transform the input -local settings_type = { - fraction = function (input) - input = tonumber(input) - - if input == nil then - return false, 'fraction setting type requires the input to be a valid number between 0 and 1.' - end - - if input < 0 then - input = 0 - end - - if input > 1 then - input = 1 - end - - return true, input - end, - string = function (input) - if input == nil then - return true, '' - end - - local input_type = type(input) - if input_type == 'string' then - return true, input - end - - if input_type == 'number' or input_type == 'boolean' then - return true, tostring(input) - end - - return false, 'string setting type requires the input to be either a valid string or something that can be converted to a string.' - end, - boolean = function (input) - local input_type = type(input) - - if input_type == 'boolean' then - return true, input - end - - if input_type == 'string' then - if input == '0' or input == '' or input == 'false' or input == 'no' then - return true, false - end - if input == '1' or input == 'true' or input == 'yes' then - return true, true - end - - return true, tonumber(input) ~= nil - end - - if input_type == 'number' then - return true, input ~= 0 - end - - return false, 'boolean setting type requires the input to be either a boolean, number or string that can be transformed to a boolean.' - end, -} - -local settings = {} -local memory = {} - -Global.register(memory, function (tbl) memory = tbl end) - -local Public = {} - -Public.types = {fraction = 'fraction', string = 'string', boolean = 'boolean'} - ----Register a specific setting with a sensitization setting type. ---- ---- Available setting types: ---- - fraction (number between 0 and 1) in either number or string form ---- - string a string or anything that can be cast to a string ---- - boolean, 1, 0, yes, no, true, false or an empty string for false ---- ---- This function must be called in the control stage, i.e. not inside an event. ---- ----@param name string ----@param setting_type string ----@param default mixed -function Public.register(name, setting_type, default) - if _LIFECYCLE ~= _STAGE.control then - error(format('You can only register setting names in the control stage, i.e. not inside events. Tried setting "%s" with type "%s".', name, setting_type), 2) - end - - if settings[name] then - error(format('Trying to register setting for "%s" while it has already been registered.', name), 2) - end - - local callback = settings_type[setting_type] - if not callback then - error(format('Trying to register setting for "%s" with type "%s" while this type does not exist.', name, setting_type), 2) - end - - local setting = { - default = default, - callback = callback, - } - - settings[name] = setting - - return setting -end - ----Sets a setting to a specific value for a player. ---- ----In order to get a setting value, it has to be registered via the "register" function. ---- ----@param player_index number ----@param name string ----@param value mixed -function Public.set(player_index, name, value) - local setting = settings[name] - if not setting then - return error(format('Setting "%s" does not exist.', name), 2) - end - - local success, sanitized_value = setting.callback(value) - - if not success then - error(format('Setting "%s" failed: %s', name, sanitized_value), 2) - end - - local player_settings = memory[player_index] - if not player_settings then - player_settings = {} - memory[player_index] = player_settings - end - - player_settings[name] = sanitized_value - - return sanitized_value -end - ----Returns the value of a setting for this player. ---- ----In order to set a setting value, it has to be registered via the "register" function. ---- ----@param player_index number ----@param name string -function Public.get(player_index, name) - local setting = settings[name] - if not setting then - return error(format('Setting "%s" does not exist.', name), 2) - end - - local player_settings = memory[player_index] - if not player_settings then - return setting.default - end - - local player_setting = player_settings[name] - return player_setting ~= nil and player_setting or setting.default -end - ----Returns a table of all settings for a given player in a key => value set-up ----@param player_index number -function Public.all(player_index) - local player_settings = memory[player_index] or {} - local output = {} - for name, data in pairs(settings) do - output[name] = player_settings[name] or data.default - end - - return output -end - -return Public diff --git a/utils/state_machine.lua b/utils/state_machine.lua deleted file mode 100644 index 9d298a52..00000000 --- a/utils/state_machine.lua +++ /dev/null @@ -1,119 +0,0 @@ ---- This module provides a classical mealy/moore state machine. --- Each machine in constructed by calling new() --- States and Transitions are lazily added to the machine as transition handlers and state tick handlers are registered. --- However the state machine must be fully defined after init is done. Dynamic machine changes are currently unsupported --- An example usage can be found here: map_gen\combined\tetris\control.lua - -local Module = {} - -local Debug = require 'utils.debug' --- @dep utils.debug - -local in_state_callbacks = {} -local transaction_callbacks = {} -local max_stack_depth = 20 -local machine_count = 0 -local control_stage = _STAGE.control - ---- Transitions the supplied machine into a given state and executes all transaction_callbacks --- @param self StateMachine --- @param new_state number/string The new state to transition to -function Module.transition(self, new_state) - Debug.print(string.format('Transitioning from state %d to state %d.', self.state, new_state)) - local old_state = self.state - - local stack_depth = self.stack_depth - self.stack_depth = stack_depth + 1 - if stack_depth > max_stack_depth then - if _DEBUG then - error('[WARNING] Stack overflow at:' .. debug.traceback()) - else - log('[WARNING] Stack overflow at:' .. debug.traceback()) - end - end - - local exit_callbacks = transaction_callbacks[self.id][old_state] - if exit_callbacks then - local entry_callbacks = exit_callbacks[new_state] - if entry_callbacks then - for i = 1, #entry_callbacks do - local callback = entry_callbacks[i] - if callback then - callback() - end - end - end - end - self.state = new_state -end - ---- Is this machine in this state? --- @param self StateMachine --- @param state number/string --- @return boolean -function Module.in_state(self, state) - return self.state == state -end - ---- Invoke a machine tick. Will execute all in_state_callbacks of the given machine --- @param self StateMachine the machine, whose handlers will be invoked -function Module.machine_tick(self) - local callbacks = in_state_callbacks[self.id][self.state] - if callbacks then - for i=1, #callbacks do - local callback = callbacks[i] - if callback then - callback() - end - end - end - self.stack_depth = 0 -end - ---- Register a handler that will be invoked by StateMachine.machine_tick --- You may register multiple handlers for the same transition --- NOTICE: This function will invoke an error if called after init. Dynamic machine changes are currently unsupported --- @param self StateMachine the machine --- @param state number/string The state, that the machine will be in, when callback is invoked --- @param callback function -function Module.register_state_tick_callback(self, state, callback) - if _LIFECYCLE ~= control_stage then - error('Calling StateMachine.register_state_tick_callback after the control stage is unsupported due to desyncs.', 2) - end - in_state_callbacks[self.id][state] = in_state_callbacks[self.id][state] or {} - table.insert(in_state_callbacks[self.id][state], callback) -end - ---- Register a handler that will be invoked by StateMachine.transition --- You may register multiple handlers for the same transition --- NOTICE: This function will invoke an error if called after init. Dynamic machine changes are currently unsupported --- @param self StateMachine the machine --- @param old number/string exiting state --- @param new number/string entering state --- @param callback function -function Module.register_transition_callback(self, old, new, callback) - if _LIFECYCLE ~= control_stage then - error('Calling StateMachine.register_transition_callback after the control stage is unsupported due to desyncs.', 2) - end - transaction_callbacks[self.id][old] = transaction_callbacks[self.id][old] or {} - transaction_callbacks[self.id][old][new] = transaction_callbacks[self.id][old][new] or {} - table.insert(transaction_callbacks[self.id][old][new], callback) -end - ---- Constructs a new state machine --- @param init_state number/string The starting state of the machine --- @return StateMachine The constructed state machine object -function Module.new(init_state) - if _LIFECYCLE ~= control_stage then - error('Calling StateMachine.new after the control stage is unsupported due to desyncs.', 2) - end - machine_count = machine_count + 1 - in_state_callbacks[machine_count] = {} - transaction_callbacks[machine_count] = {} - return { - state = init_state, - stack_depth = 0, - id = machine_count, - } -end - -return Module diff --git a/utils/timestamp.lua b/utils/timestamp.lua deleted file mode 100644 index 3c2eb73e..00000000 --- a/utils/timestamp.lua +++ /dev/null @@ -1,152 +0,0 @@ ---- source https://github.com/daurnimator/luatz/blob/master/luatz/timetable.lua --- edited down to just what is needed. - -local Public = {} - -local floor = math.floor -local strformat = string.format - -local function borrow(tens, units, base) - local frac = tens % 1 - units = units + frac * base - tens = tens - frac - return tens, units -end - -local function carry(tens, units, base) - if units >= base then - tens = tens + floor(units / base) - units = units % base - elseif units < 0 then - tens = tens + floor(units / base) - units = (base + units) % base - end - return tens, units -end - -local function is_leap(y) - if (y % 4) ~= 0 then - return false - elseif (y % 100) ~= 0 then - return true - else - return (y % 400) == 0 - end -end - -local mon_lengths = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} - --- Number of days in year until start of month; not corrected for leap years -local months_to_days_cumulative = {0} -for i = 2, 12 do - months_to_days_cumulative[i] = months_to_days_cumulative[i - 1] + mon_lengths[i - 1] -end - -local function month_length(m, y) - if m == 2 then - return is_leap(y) and 29 or 28 - else - return mon_lengths[m] - end -end - -local function day_of_year(day, month, year) - local y_day = months_to_days_cumulative[month] - if month > 2 and is_leap(year) then - y_day = y_day + 1 - end - return y_day + day -end - -local function leap_years_since(year) - return floor(year / 4) - floor(year / 100) + floor(year / 400) -end - -local leap_years_since_1970 = leap_years_since(1970) - -local function normalise(year, month, day, hour, min, sec) - -- `month` and `day` start from 1, need -1 and +1 so it works modulo - month, day = month - 1, day - 1 - - -- Convert everything (except seconds) to an integer - -- by propagating fractional components down. - year, month = borrow(year, month, 12) - -- Carry from month to year first, so we get month length correct in next line around leap years - year, month = carry(year, month, 12) - month, day = borrow(month, day, month_length(floor(month + 1), year)) - day, hour = borrow(day, hour, 24) - hour, min = borrow(hour, min, 60) - min, sec = borrow(min, sec, 60) - - -- Propagate out of range values up - -- e.g. if `min` is 70, `hour` increments by 1 and `min` becomes 10 - -- This has to happen for all columns after borrowing, as lower radix's may be pushed out of range - min, sec = carry(min, sec, 60) -- TODO: consider leap seconds? - hour, min = carry(hour, min, 60) - day, hour = carry(day, hour, 24) - -- Ensure `day` is not underflowed - -- Add a whole year of days at a time, this is later resolved by adding months - -- TODO[OPTIMIZE]: This could be slow if `day` is far out of range - while day < 0 do - month = month - 1 - if month < 0 then - year = year - 1 - month = 11 - end - day = day + month_length(month + 1, year) - end - year, month = carry(year, month, 12) - - -- TODO[OPTIMIZE]: This could potentially be slow if `day` is very large - while true do - local i = month_length(month + 1, year) - if day < i then - break - end - day = day - i - month = month + 1 - if month >= 12 then - month = 0 - year = year + 1 - end - end - - -- Now we can place `day` and `month` back in their normal ranges - -- e.g. month as 1-12 instead of 0-11 - month, day = month + 1, day + 1 - - return {year = year, month = month, day = day, hour = hour, min = min, sec = sec} -end - ---- Converts unix epoch timestamp into table {year: number, month: number, day: number, hour: number, min: number, sec: number} --- @param seconds unix epoch timestamp --- @return {year: number, month: number, day: number, hour: number, min: number, sec: number} -function Public.to_timetable(seconds) - return normalise(1970, 1, 1, 0, 0, seconds) -end - ---- Converts timetable into unix epoch timestamp --- @param timetable
{year: number, month: number, day: number, hour: number, min: number, sec: number} --- @return number -function Public.from_timetable(timetable) - local tt = normalise(timetable.year, timetable.month, timetable.day, timetable.hour, timetable.min, timetable.sec) - - local year, month, day, hour, min, sec = tt.year, tt.month, tt.day, tt.hour, tt.min, tt.sec - - local days_since_epoch = - day_of_year(day, month, year) + 365 * (year - 1970) + -- Each leap year adds one day - (leap_years_since(year - 1) - leap_years_since_1970) - - 1 - - return days_since_epoch * (60 * 60 * 24) + hour * (60 * 60) + min * 60 + sec -end - ---- Converts unix epoch timestamp into human readable string. --- @param seconds unix epoch timestamp --- @return string -function Public.to_string(seconds) - local tt = normalise(1970, 1, 1, 0, 0, seconds) - return strformat('%04u-%02u-%02u %02u:%02u:%02d', tt.year, tt.month, tt.day, tt.hour, tt.min, tt.sec) -end - -return Public