Moved All Code Out Of Locale

This commit is contained in:
Cooldude2606
2017-12-16 00:33:27 +00:00
parent 4f12463c73
commit 592761c4af
17 changed files with 4 additions and 4 deletions

314
StdLib/color.lua Normal file
View File

@@ -0,0 +1,314 @@
--- A defines module for retrieving colors by name.
-- Extends the Factorio defines table.
-- @usage require('stdlib/defines/color')
-- @module defines.color
-- @see Concepts.Color
-- defines table is automatically required in all mod loading stages.
-- luacheck: ignore 122/defines
-- Ignore assigning to read only defines table. defines table is not ready only, however
-- marking it this way allows warnings to be generated when trying to assign values
defines = defines or {} --luacheck: ignore defines (This is used for testing locally)
--- A table of colors allowing retrieval by color name.
-- @usage color = defines.color.red
-- @tfield Concepts.Color white
-- @tfield Concepts.Color black
-- @tfield Concepts.Color darkgrey
-- @tfield Concepts.Color grey
-- @tfield Concepts.Color lightgrey
-- @tfield Concepts.Color red
-- @tfield Concepts.Color darkred
-- @tfield Concepts.Color lightred
-- @tfield Concepts.Color green
-- @tfield Concepts.Color darkgreen
-- @tfield Concepts.Color lightgreen
-- @tfield Concepts.Color blue
-- @tfield Concepts.Color darkblue
-- @tfield Concepts.Color lightblue
-- @tfield Concepts.Color orange
-- @tfield Concepts.Color yellow
-- @tfield Concepts.Color pink
-- @tfield Concepts.Color purple
-- @tfield Concepts.Color brown
defines.color = {}
local colors = {
white = {r = 1.00, g = 1.00, b = 1.00},
black = {r = 0.00, g = 0.00, b = 0.00},
darkgrey = {r = 0.25, g = 0.25, b = 0.25},
grey = {r = 0.50, g = 0.50, b = 0.50},
lightgrey = {r = 0.75, g = 0.75, b = 0.75},
red = {r = 1.00, g = 0.00, b = 0.00},
darkred = {r = 0.50, g = 0.00, b = 0.00},
lightred = {r = 1.00, g = 0.50, b = 0.50},
green = {r = 0.00, g = 1.00, b = 0.00},
darkgreen = {r = 0.00, g = 0.50, b = 0.00},
lightgreen = {r = 0.50, g = 1.00, b = 0.50},
blue = {r = 0.00, g = 0.00, b = 1.00},
darkblue = {r = 0.00, g = 0.00, b = 0.50},
lightblue = {r = 0.50, g = 0.50, b = 1.00},
orange = {r = 1.00, g = 0.55, b = 0.10},
yellow = {r = 1.00, g = 1.00, b = 0.00},
pink = {r = 1.00, g = 0.00, b = 1.00},
purple = {r = 0.60, g = 0.10, b = 0.60},
brown = {r = 0.60, g = 0.40, b = 0.10}
}
--- Returns white for dark colors or black for lighter colors.
-- @tfield Concepts.Color green defines.color.black
-- @tfield Concepts.Color grey defines.color.black
-- @tfield Concepts.Color lightblue defines.color.black
-- @tfield Concepts.Color lightgreen defines.color.black
-- @tfield Concepts.Color lightgrey defines.color.black
-- @tfield Concepts.Color lightred defines.color.black
-- @tfield Concepts.Color orange defines.color.black
-- @tfield Concepts.Color white defines.color.black
-- @tfield Concepts.Color yellow defines.color.black
-- @tfield Concepts.Color black defines.color.white
-- @tfield Concepts.Color blue defines.color.white
-- @tfield Concepts.Color brown defines.color.white
-- @tfield Concepts.Color darkblue defines.color.white
-- @tfield Concepts.Color darkgreen defines.color.white
-- @tfield Concepts.Color darkgrey defines.color.white
-- @tfield Concepts.Color darkred defines.color.white
-- @tfield Concepts.Color pink defines.color.white
-- @tfield Concepts.Color purple defines.color.white
-- @tfield Concepts.Color red defines.color.white
defines.anticolor = {}
local anticolors = {
green = colors.black,
grey = colors.black,
lightblue = colors.black,
lightgreen = colors.black,
lightgrey = colors.black,
lightred = colors.black,
orange = colors.black,
white = colors.black,
yellow = colors.black,
black = colors.white,
blue = colors.white,
brown = colors.white,
darkblue = colors.white,
darkgreen = colors.white,
darkgrey = colors.white,
darkred = colors.white,
pink = colors.white,
purple = colors.white,
red = colors.white
}
--- Returns a lighter color of a named color.
-- @tfield Concepts.Color white defines.color.lightgrey
-- @tfield Concepts.Color grey defines.color.darkgrey
-- @tfield Concepts.Color lightgrey defines.color.grey
-- @tfield Concepts.Color red defines.color.lightred
-- @tfield Concepts.Color green defines.color.lightgreen
-- @tfield Concepts.Color blue defines.color.lightblue
-- @tfield Concepts.Color yellow defines.color.orange
-- @tfield Concepts.Color pink defines.color.purple
defines.lightcolor = {}
local lightcolors = {
white = colors.lightgrey,
grey = colors.darkgrey,
lightgrey = colors.grey,
red = colors.lightred,
green = colors.lightgreen,
blue = colors.lightblue,
yellow = colors.orange,
pink = colors.purple
}
-- added by cooldude2606
--- Returns a lighter color of a named color.
-- @tfield Concepts.Color info
-- @tfield Concepts.Color bg
-- @tfield Concepts.Color low
-- @tfield Concepts.Color med
-- @tfield Concepts.Color high
-- @tfield Concepts.Color crit
defines.text_color = {}
local text_color = {
info = {r = 0.21, g = 0.95, b = 1.00},
bg = {r = 0.00, g = 0.00, b = 0.00},
low = {r = 0.18, g = 0.77, b = 0.18},
med = {r = 1.00, g = 0.89, b = 0.26},
high = {r = 1.00, g = 0.33, b = 0.00},
crit = {r = 1.00, g = 0.00, b = 0.00}
}
local _mt = {
color = {
__index = function(_, c)
return colors[c]
and { r = colors[c]['r'], g=colors[c]['g'], b=colors[c]['b'], a = colors[c]['a'] }
or { r = 1, g = 1, b = 1, a = 1 }
end,
__pairs = function()
local k = nil
local c = colors
return function()
local v
k, v = next(c, k)
return k, (v and {r = v['r'], g = v['g'], b = v['b'], a = v['a']}) or nil
end
end
},
anticolor = {
__index = function(_, c)
return anticolors[c]
and { r = anticolors[c]['r'], g=anticolors[c]['g'], b=anticolors[c]['b'], a = anticolors[c]['a'] }
or { r = 1, g = 1, b = 1, a = 1 }
end,
__pairs = function()
local k = nil
local c = anticolors
return function()
local v
k, v = next(c, k)
return k, (v and {r = v['r'], g = v['g'], b = v['b'], a = v['a']}) or nil
end
end
},
lightcolor = {
__index = function(_, c)
return lightcolors[c]
and { r = lightcolors[c]['r'], g=lightcolors[c]['g'], b=lightcolors[c]['b'], a = lightcolors[c]['a'] }
or { r = 1, g = 1, b = 1, a = 1 }
end,
__pairs = function()
local k = nil
local c = lightcolors
return function()
local v
k, v = next(c, k)
return k, (v and {r = v['r'], g = v['g'], b = v['b'], a = v['a']}) or nil
end
end
},
text_color = { -- added by cooldude2606
__index = function(_, c)
return text_color[c]
and { r = text_color[c]['r'], g=text_color[c]['g'], b=text_color[c]['b'], a = text_color[c]['a'] }
or { r = 1, g = 1, b = 1, a = 1 }
end,
__pairs = function()
local k = nil
local c = text_color
return function()
local v
k, v = next(c, k)
return k, (v and {r = v['r'], g = v['g'], b = v['b'], a = v['a']}) or nil
end
end
}
}
setmetatable(defines.color, _mt.color)
setmetatable(defines.anticolor, _mt.anticolor)
setmetatable(defines.text_color, _mt.text_color)
setmetatable(defines.lightcolor, _mt.lightcolor)
--- For playing with colors.
-- @module Color
-- @usage local Color = require('stdlib/color/color')
--require 'stdlib/defines/color'
local fail_if_missing = require 'game'['fail_if_missing']
local Color = {} --luacheck: allow defined top
--- Set a value for the alpha channel in the given color table.
-- `color.a` represents the alpha channel in the given color table.
-- <ul>
-- <li>If ***alpha*** is given, set `color.a` to it.
-- <li>If ***alpha*** is not given, and if the given color table does not have a value for `color.a`, set `color.a` to 1.
-- <li>If ***alpha*** is not given, and if the given color table already has a value for `color.a`, then leave `color.a` alone.
-- </ul>
-- @tparam[opt=white] defines.color|Concepts.Color color the color to configure
-- @tparam[opt=1] float alpha the alpha value (*[0 - 1]*) to set for the given color
-- @treturn Concepts.Color a color table that has the specified value for the alpha channel
function Color.set(color, alpha)
color = color or defines.color.white
Color.to_table(color)
color.a = alpha or color.a or 1
return color
end
--- Converts a color in the array format to a color in the table format.
-- @tparam array c_arr the color to convert &mdash; { [1] = @{float}, [2] = @{float}, [3] = @{float}, [4] = @{float} }
-- @treturn Concepts.Color a converted color &mdash; { r = c\_arr[1], g = c\_arr[2], b = c\_arr[3], a = c\_arr[4] }
function Color.to_table(c_arr)
if #c_arr > 0 then
return {r = c_arr[1], g = c_arr[2], b = c_arr[3], a = c_arr[4]}
end
return c_arr
end
--- Converts a color in the rgb format to a color table
-- @tparam[opt=0] int r 0-255 red
-- @tparam[opt=0] int g 0-255 green
-- @tparam[opt=0] int b 0-255 blue
-- @tparam[opt=255] int a 0-255 alpha
-- @treturn Concepts.Color
function Color.from_rgb(r, g, b, a)
r = r or 0
g = g or 0
b = b or 0
a = a or 255
return {r = r/255, g = g/255, b = b/255, a = a/255}
end
--- Get a color table with a hexadecimal string.
-- Optionally provide the value for the alpha channel.
-- @tparam string hex hexadecimal color string (#ffffff, not #fff)
-- @tparam[opt=1] float alpha the alpha value to set; such that ***[ 0 &#8924; value &#8924; 1 ]***
-- @treturn Concepts.Color a color table with RGB converted from Hex and with alpha
function Color.from_hex(hex, alpha)
fail_if_missing(hex, "missing color hex value")
if hex:find("#") then hex = hex:sub(2) end
if not(#hex == 6) then error("invalid color hex value: "..hex) end
local number = tonumber(hex, 16)
return {
r = bit32.extract(number, 16, 8) / 255,
g = bit32.extract(number, 8, 8) / 255,
b = bit32.extract(number, 0, 8) / 255,
a = alpha or 1
}
end
--added by cooldude2606
--- Converts a color in the color table format to rgb
-- @tparam table color the color to convert
-- @treturn table the color as rgb
function Color.to_rgb(color)
local r = color.r or 0
local g = color.g or 0
local b = color.b or 0
local a = color.a or 0.5
return {r = r*255, g = g*255, b = b*255, a = a*255}
end
--added by cooldude2606
--- Converts a color in the color table format to hex
-- @tparam table color the color to convert
-- @treturn string the color as hex
function Color.to_hex(color)
local hexadecimal = '0x'
for key, value in pairs{math.floor(color.r*255),math.floor(color.g*255),math.floor(color.b*255)} do
local hex = ''
while(value > 0)do
local index = math.fmod(value, 16) + 1
value = math.floor(value / 16)
hex = string.sub('0123456789ABCDEF', index, index) .. hex
end
if string.len(hex) == 0 then hex = '00'
elseif string.len(hex) == 1 then hex = '0' .. hex
end
hexadecimal = hexadecimal .. hex
end
return hexadecimal
end
return Color

173
StdLib/event.lua Normal file
View File

@@ -0,0 +1,173 @@
--- Makes working with events in factorio a lot more simple.
-- <p>Factorio can only have one handler registered per event. This module
-- allows you to easily register multiple handlers for each event.
-- Using this module is as simple as replacing script.on_event(...) with Event.register(...)</p>
-- @module Event
-- @usage require('stdlib/event/event')
local fail_if_missing = require 'game'['fail_if_missing']
local Game = require 'game'
local Event = { --luacheck: allow defined top
_registry = {},
core_events = {
init = -1,
load = -2,
configuration_changed = -3,
_register = function(id)
if id == Event.core_events.init then
script.on_init(
function()
Event.dispatch({name = Event.core_events.init, tick = game.tick})
end
)
elseif id == Event.core_events.load then
script.on_load(
function()
Event.dispatch({name = Event.core_events.load, tick = -1})
end
)
elseif id == Event.core_events.configuration_changed then
script.on_configuration_changed(
function(event)
event.name = Event.core_events.configuration_changed
event.data = event -- for backwards compatibilty
Event.dispatch(event)
end
)
end
end
}
}
--[[ edit by cooldude2606 to allow change during run-time without desyncs -- still going to use this but FACTORIO NO LIKE
Event.__registry = Event._registry
Event._registry = function()
if game and global then
if not global.event_registry then global.event_registry = Event.__registry end
return global.event_registry
end
return Event.__registry
end]]
--- Registers a function for a given event. If a nil handler is passed remove all events and stop listening for that event.
-- Events are dispatched in the order they are registered.
-- @usage Event.register(defines.events.on_tick, function(event) print event.tick end)
-- -- creates an event that prints the current tick every tick.
-- @tparam defines.events|{defines.events,...} event events to register
-- @tparam function handler Function to call when event is triggered
-- @treturn Event
function Event.register(event, handler)
fail_if_missing(event, "missing event argument")
event = (type(event) == "table" and event) or {event}
for _, event_id in pairs(event) do
if not (type(event_id) == "number" or type(event_id) == "string") then
error("Invalid Event Id, Must be string or int, or array of strings and/or ints", 2)
end
if handler == nil then
Event._registry[event_id] = nil
script.on_event(event_id, nil)
else
if not Event._registry[event_id] then
Event._registry[event_id] = {}
if type(event_id) == "string" or event_id >= 0 then
script.on_event(event_id, Event.dispatch)
elseif event_id < 0 then
Event.core_events._register(event_id)
end
end
table.insert(Event._registry[event_id], handler)
end
end
return Event
end
--- Calls the registerd handlers
-- Will stop dispatching remaning handlers if any handler passes invalid event userdata.
-- Handlers are dispatched in the order they were created
-- @tparam table event LuaEvent as created by script.raise_event
-- @see https://forums.factorio.com/viewtopic.php?t=32039#p202158 Invalid Event Objects
function Event.dispatch(event)
if event then
local _registry = event.name and Event._registry[event.name] or event.input_name and Event._registry[event.input_name]
if _registry then
local force_crc = Event.force_crc
for idx, handler in ipairs(_registry) do
-- Check for userdata and stop processing further handlers if not valid
for _, val in pairs(event) do
if type(val) == "table" and val.__self == "userdata" and not val.valid then
return
end
end
setmetatable(event, { __index = { _handler = handler } })
-- Call the handler
local success, err = pcall(handler, event)
-- If the handler errors lets make sure someone notices
if not success then
if _G.game then -- may be nil in on_load
-- edit by cooldude2606 custom error haddle
--if Game.print_all(err) == 0 then
--error(err) -- no players received the message, force a real error so someone notices
--end
error(err)
else
error(err) -- no way to handle errors cleanly when the game is not up
end
-- continue processing the remaning handlers. In most cases they won't be related to the failed code.
end
-- force a crc check if option is enabled. This is a debug option and will hamper perfomance if enabled
if (force_crc or event.force_crc) and _G.game then
local msg = 'CRC check called for event '..event.name..' handler #'..idx
log(msg) -- log the message to factorio-current.log
game.force_crc()
end
-- if present stop further handlers for this event
if event.stop_processing then
return
end
end
end
else
error('missing event argument')
end
end
--- Removes the handler from the event. If it removes the last handler for an event stop listening for that event.
-- @tparam defines.events|{defines.events,...} event events to remove the handler for
-- @tparam function handler to remove
-- @return Event
function Event.remove(event, handler)
fail_if_missing(event, "missing event argument")
fail_if_missing(handler, "missing handler argument")
event = (type(event) == "table" and event) or {event}
for _, event_id in pairs(event) do
if not (type(event_id) == "number" or type(event_id) == "string") then
error("Invalid Event Id, Must be string or int, or array of strings and/or ints", 2)
end
if Event._registry[event_id] then
for i=#Event._registry[event_id], 1, -1 do
if Event._registry[event_id][i] == handler then
table.remove(Event._registry[event_id], i)
end
end
if #Event._registry[event_id] == 0 then
Event._registry[event_id] = nil
script.on_event(event_id, nil)
end
end
end
return Event
end
return Event

103
StdLib/game.lua Normal file
View File

@@ -0,0 +1,103 @@
--- The game module.
-- @module Game
-- @usage local Game = require('stdlib/game')
local Game = { --luacheck: allow defined top
VALID_FILTER = function(v)
return v and v.valid
end,
_protect = function(module_name)
return {
__newindex = function() error("Attempt to mutatate read-only "..module_name.." Module") end,
__metatable = true
}
end,
_concat = function(lhs, rhs)
--Sanatize to remove address
return tostring(lhs):gsub("(%w+)%: %x+", "%1: (ADDR)") .. tostring(rhs):gsub("(%w+)%: %x+", "%1: (ADDR)")
end,
_rawstring = function (t)
local m = getmetatable(t)
local f = m.__tostring
m.__tostring = nil
local s = tostring(t)
m.__tostring = f
return s
end
}
-- No Doc
-- This is a helper global and functions until .16
-- to set the name of your mod in control.lua set _stdlib_mod_name = 'name of your mod'
-- luacheck: ignore _stdlib_mod_name
function Game.get_mod_name()
local ok, mod_name = pcall(function() return script.mod_name end)
return ok and mod_name or _stdlib_mod_name or "stdlib"
end
--- Print msg if specified var evaluates to false.
-- @tparam Mixed var variable to evaluate
-- @tparam[opt="missing value"] string msg message
function Game.fail_if_missing(var, msg)
if not var then
error(msg or "Missing value", 3)
end
return false
end
--- Return a valid player object from event, index, string, or userdata
-- @tparam string|number|LuaPlayer|event mixed
-- @treturn LuaPlayer a valid player or nil
function Game.get_player(mixed)
if type(mixed) == "table" then
if mixed.__self then
return mixed and mixed.valid and mixed
elseif mixed.player_index then
local player = game.players[mixed.player_index]
return player and player.valid and player
end
elseif mixed then
local player = game.players[mixed]
return player and player.valid and player
end
end
--- Return a valid force object from event, string, or userdata
-- @tparam string|LuaForce|event mixed
-- @treturn LuaForce a valid force or nil
function Game.get_force(mixed)
if type(mixed) == "table" then
if mixed.__self then
return mixed and mixed.valid and mixed
elseif mixed.force then
return Game.get_force(mixed.force)
end
elseif type(mixed) == "string" then
local force = game.forces[mixed]
return (force and force.valid) and force
end
end
--- Messages all players currently connected to the game.
--> Offline players are not counted as having received the message.
-- If no players exist msg is stored in the `global._print_queue` table.
-- @tparam string msg the message to send to players
-- @tparam[opt] ?|nil|boolean condition the condition to be true for a player to be messaged
-- @treturn uint the number of players who received the message.
function Game.print_all(msg, condition)
local num = 0
if #game.players > 0 then
for _, player in pairs(game.players) do
if condition == nil or select(2, pcall(condition, player)) then
player.print(msg)
num = num + 1
end
end
return num
else
global._print_queue = global._print_queue or {}
global._print_queue[#global._print_queue + 1] = msg
end
end
return Game

35
StdLib/load.lua Normal file
View File

@@ -0,0 +1,35 @@
--[[
Explosive Gaming
This file can be used with permission but this and the credit below must remain in the file.
Contact a member of management on our discord to seek permission to use our code.
Any changes that you may make to the code are yours but that does not make the script yours.
Discord: https://discord.gg/r6dC2uK
]]
--[[
StdLib
This file allow you to only require this one file to return the diffent libarys.
This file will return a function which can be used to access only the part you want.
Pass a table with the names of the objects you want and it will be return in that order
]]
local StdLib = {}
require '/table'
require '/string'
require '/time'
StdLib.Color = require '/color'
StdLib.Game = require '/game'
StdLib.Event = require '/event'
return function(rtn)
local _return = {}
for _,name in pairs(rtn) do
if StdLib[name] then
table.insert(_return,StdLib[name])
end
end
return unpack(_return)
end

86
StdLib/string.lua Normal file
View File

@@ -0,0 +1,86 @@
--- Extends Lua 5.2 string.
-- @module string
-- @see string
-- luacheck: globals string (Allow mutating string)
--- Returns a copy of the string with any leading or trailing whitespace from the string removed.
-- @tparam string s the string to remove leading or trailing whitespace from
-- @treturn string a copy of the string without leading or trailing whitespace
function string.trim(s)
return (s:gsub("^%s*(.-)%s*$", "%1"))
end
--- Tests if a string starts with a given substring.
-- @tparam string s the string to check for the start substring
-- @tparam string start the substring to test for
-- @treturn boolean true if the start substring was found in the string
function string.starts_with(s, start)
return string.find(s, start, 1, true) == 1
end
--- Tests if a string ends with a given substring.
-- @tparam string s the string to check for the end substring
-- @tparam string ends the substring to test for
-- @treturn boolean true if the end substring was found in the string
function string.ends_with(s, ends)
return #s >= #ends and string.find(s, ends, #s - #ends + 1, true) and true or false
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 string.contains(s, contains)
return s and string.find(s, contains) ~= nil
end
--- Tests whether a string is empty.
-- @tparam string s the string to test
-- @treturn boolean true if the string is empty
function string.is_empty(s)
return s == nil or s == ''
end
--- Splits a string into an array.
-- *Note:* Empty split substrings are not included in the resulting table.
-- <p>For example, `string.split("foo.bar...", ".", false)` results in the table `{"foo", "bar"}`.
-- @tparam string s the string to split
-- @tparam[opt="."] string sep the separator to use.
-- @tparam[opt=false] boolean pattern whether to interpret the separator as a lua pattern or plaintext for the string split
-- @treturn {string,...} an array of strings
function string.split(s, sep, pattern)
sep = sep or "."
sep = sep ~= "" and sep or "."
sep = not pattern and string.gsub(sep, "([^%w])", "%%%1") or sep
local fields = {}
local start_idx, end_idx = string.find(s, sep)
local last_find = 1
while start_idx do
local substr = string.sub(s, last_find, start_idx - 1)
if string.len(substr) > 0 then
table.insert(fields, string.sub(s, last_find, start_idx - 1))
end
last_find = end_idx + 1
start_idx, end_idx = string.find(s, sep, end_idx + 1)
end
local substr = string.sub(s, last_find)
if string.len(substr) > 0 then
table.insert(fields, string.sub(s, last_find))
end
return fields
end
-- added by cooldude2606
--- Returns a string as a hex format (also a string)
-- @usage a = 'foo'
-- string.to_hex(a) -- return '666f6f'
-- @tparam string str the string to encode
-- @treturn string the hex format of the string
function string.to_hex(str)
if not is_type(str,'string') then return '' end
return str:gsub('.',function (c)
return string.format('%02X',string.byte(c))
end)
end

497
StdLib/table.lua Normal file
View File

@@ -0,0 +1,497 @@
--- Extends Lua 5.2 table.
-- @module table
-- @see table
-- luacheck: globals table (Allow mutating global table)
--- Given a mapping function, creates a transformed copy of the table
--- by calling the function for each element in the table, and using
--- the result as the new value for the key. Passes the index as second argument to the function.
--- @usage a= { 1, 2, 3, 4, 5}
---table.map(a, function(v) return v * 10 end) --produces: { 10, 20, 30, 40, 50 }
--- @usage a = {1, 2, 3, 4, 5}
---table.map(a, function(v, k, x) return v * k + x end, 100) --produces { 101, 104, 109, 116, 125}
-- @tparam table tbl the table to be mapped to the transform
-- @tparam function func the function to transform values
-- @param[opt] ... additional arguments passed to the function
-- @treturn table a new table containing the keys and mapped values
function table.map(tbl, func, ...)
local newtbl = {}
for i, v in pairs(tbl) do
newtbl[i] = func(v, i, ...)
end
return newtbl
end
--- Given a filter function, creates a filtered copy of the table
--- by calling the function for each element in the table, and
--- filtering out any key-value pairs for non-true results. Passes the index as second argument to the function.
--- @usage a= { 1, 2, 3, 4, 5}
---table.filter(a, function(v) return v % 2 == 0 end) --produces: { 2, 4 }
--- @usage a = {1, 2, 3, 4, 5}
---table.filter(a, function(v, k, x) return k % 2 == 1 end) --produces: { 1, 3, 5 }
-- @tparam table tbl the table to be filtered
-- @tparam function func the function to filter values
-- @param[opt] ... additional arguments passed to the function
-- @treturn table a new table containing the filtered key-value pairs
function table.filter(tbl, func, ...)
local newtbl = {}
local insert = #tbl > 0
for k, v in pairs(tbl) do
if func(v, k, ...) then
if insert then table.insert(newtbl, v)
else newtbl[k] = v end
end
end
return newtbl
end
--- Given a candidate search function, iterates over the table, calling the function
--- for each element in the table, and returns the first element the search function returned true.
--- Passes the index as second argument to the function.
--- @usage a= { 1, 2, 3, 4, 5}
---table.find(a, function(v) return v % 2 == 0 end) --produces: 2
--- @usage a = {1, 2, 3, 4, 5}
---table.find(a, function(v, k, x) return k % 2 == 1 end) --produces: 1
-- @tparam table tbl the table to be searched
-- @tparam function func the function to use to search for any matching element
-- @param[opt] ... additional arguments passed to the function
-- @treturn ?|nil|Mixed the first found value, or nil if none was found
function table.find(tbl, func, ...)
for k, v in pairs(tbl) do
if func(v, k, ...) then
return v, k
end
end
return nil
end
--- Given a candidate search function, iterates over the table, calling the function
-- for each element in the table, and returns true if search function returned true.
-- Passes the index as second argument to the function.
-- @see table.find
--- @usage a= { 1, 2, 3, 4, 5}
---table.any(a, function(v) return v % 2 == 0 end) --produces: true
--- @usage a = {1, 2, 3, 4, 5}
---table.any(a, function(v, k, x) return k % 2 == 1 end) --produces: true
-- @tparam table tbl the table to be searched
-- @tparam function func the function to use to search for any matching element
-- @param[opt] ... additional arguments passed to the function
-- @treturn boolean true if an element was found, false if none was found
function table.any(tbl, func, ...)
return table.find(tbl, func, ...) ~= nil
end
--- Given a function, apply it to each element in the table.
-- Passes the index as the second argument to the function.
-- <p>Iteration is aborted if the applied function returns true for any element during iteration.
-- @usage
-- a = {10, 20, 30, 40}
-- table.each(a, function(v) game.print(v) end) --prints 10, 20, 30, 40, 50
-- @tparam table tbl the table to be iterated
-- @tparam function func the function to apply to elements
-- @param[opt] ... additional arguments passed to the function
-- @treturn table the table where the given function has been applied to its elements
function table.each(tbl, func, ...)
for k, v in pairs(tbl) do
if func(v, k, ...) then
break
end
end
return tbl
end
--- Returns a new array that is a one-dimensional recursive flattening of the given array.
-- For every element that is an array, extract its elements into the new array.
-- <p>The optional level argument determines the level of recursion to flatten.
--> This function flattens an integer-indexed array, but not an associative array.
-- @tparam array tbl the array to be flattened
-- @tparam[opt] uint level recursive levels, or no limit to recursion if not supplied
-- @treturn array a new array that represents the flattened contents of the given array
function table.flatten(tbl, level)
local flattened = {}
table.each(tbl,
function(value)
if type(value) == "table" and #value > 0 then
if level then
if level > 0 then
table.merge(flattened, table.flatten(value, level - 1), true)
else
table.insert(flattened, value)
end
else
table.merge(flattened, table.flatten(value), true)
end
else
table.insert(flattened, value)
end
end
)
return flattened
end
--- Given an array, returns the first element or nil if no element exists.
-- @tparam array tbl the array
-- @treturn ?|nil|Mixed the first element
function table.first(tbl)
return tbl[1]
end
--- Given an array, returns the last element or nil if no elements exist.
-- @tparam array tbl the array
-- @treturn ?|nil|Mixed the last element or nil
function table.last(tbl)
local size = #tbl
if size == 0 then return nil end
return tbl[size]
end
--- Given an array of only numeric values, returns the minimum or nil if no element exists.
-- @tparam {number,...} tbl the array with only numeric values
-- @treturn ?|nil|number the minimum value
function table.min(tbl)
if #tbl == 0 then return nil end
local min = tbl[1]
for _, num in pairs(tbl) do
min = num < min and num or min
end
return min
end
---Given an array of only numeric values, returns the maximum or nil if no element exists.
-- @tparam {number,...} tbl the array with only numeric values
-- @treturn ?|nil|number the maximum value
function table.max(tbl)
if #tbl == 0 then return nil end
local max = tbl[1]
for _, num in pairs(tbl) do
max = num > max and num or max
end
return max
end
--- Given an array of only numeric values, return the sum of all values, or 0 for empty arrays.
-- @tparam {number,...} tbl the array with only numeric values
-- @treturn number the sum of the numbers or zero if the given array was empty
function table.sum(tbl)
local sum = 0
for _, num in pairs(tbl) do
sum = sum + num
end
return sum
end
--- Given an array of only numeric values, returns the average or nil if no element exists.
-- @tparam {number,...} tbl the array with only numeric values
-- @treturn ?|nil|number the average value
function table.avg(tbl)
local cnt = #tbl
return cnt ~= 0 and table.sum(tbl) / cnt or nil
end
--- Merges two tables &mdash; values from first get overwritten by the second.
--- @usage
-- function some_func(x, y, args)
-- args = table.merge({option1=false}, args)
-- if opts.option1 == true then return x else return y end
-- end
-- some_func(1,2) -- returns 2
-- some_func(1,2,{option1=true}) -- returns 1
-- @tparam table tblA first table
-- @tparam table tblB second table
-- @tparam[opt=false] boolean array_merge set to true to merge the tables as an array or false for an associative array
-- @treturn array|table an array or an associated array where tblA and tblB have been merged
function table.merge(tblA, tblB, array_merge)
if not tblB then
return tblA
end
if array_merge then
for _, v in pairs(tblB) do
table.insert(tblA, v)
end
else
for k, v in pairs(tblB) do
tblA[k] = v
end
end
return tblA
end
-- copied from factorio/data/core/luablib/util.lua
--- Creates a deep copy of table without copying Factorio objects.
-- @usage local copy = table.deepcopy[data.raw.["stone-furnace"]["stone-furnace"]] -- returns a copy of the stone furnace entity
-- @tparam table object the table to copy
-- @treturn table a copy of the table
function table.deepcopy(object)
local lookup_table = {}
local function _copy(this_object)
if type(this_object) ~= "table" then
return this_object
elseif this_object.__self then
return this_object
elseif lookup_table[this_object] then
return lookup_table[this_object]
end
local new_table = {}
lookup_table[this_object] = new_table
for index, value in pairs(this_object) do
new_table[_copy(index)] = _copy(value)
end
return setmetatable(new_table, getmetatable(this_object))
end
return _copy(object)
end
--- Returns a copy of all of the values in the table.
-- @tparam table tbl the table 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.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,
function(x, y) --sorts tables with mixed index types.
local tx = type(x) == 'number'
local ty = type(y) == 'number'
if tx == ty then
return x < y and true or false --similar type can be compared
elseif tx == true then
return true --only x is a number and goes first
else
return false --only y is a number and goes first
end
end
)
end
return valueset
end
--- Returns a copy of all of the keys in the table.
-- @tparam table tbl the table 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.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,
function(x, y) --sorts tables with mixed index types.
local tx = type(x) == 'number'
local ty = type(y) == 'number'
if tx == ty then
return x < y and true or false --similar type can be compared
elseif tx == true then
return true --only x is a number and goes first
else
return false --only y is a number and goes first
end
end
)
end
return keyset
end
--- Removes keys from a table by setting the values associated with the keys to nil.
-- @usage local a = {1, 2, 3, 4}
--table.remove_keys(a, {1,3}) --returns {nil, 2, nil, 4}
-- @usage local b = {k1 = 1, k2 = 'foo', old_key = 'bar'}
--table.remove_keys(b, {'old_key'}) --returns {k1 = 1, k2 = 'foo'}
-- @tparam table tbl the table to remove the keys from
-- @tparam {Mixed,...} keys an array of keys that exist in the given table
-- @treturn table tbl without the specified keys
function table.remove_keys(tbl, keys)
for i = 1, #keys do
tbl[keys[i]] = nil
end
return tbl
end
--- Returns the number of keys in a table, if func is passed only count keys when the function is true.
-- @tparam table tbl to count keys
-- @tparam[opt] function func to incremement counter
-- @param[optchain] ... additional arguments passed to the function
-- @treturn number The number of keys matching the function or the number of all keys if func isn't passed
-- @treturn number The total number of keys
-- @usage local a = { 1, 2, 3, 4, 5}
-- table.count_keys(a) -- produces: 5, 5
-- @usage local a = {1, 2, 3, 4, 5}
-- table.count_keys(a, function(v, k) return k % 2 == 1 end) -- produces: 3, 5
function table.count_keys(tbl, func, ...)
if type(tbl) ~= 'table' then return 0, 0 end
local count, total = 0, 0
for k, v in pairs(tbl) do
total = total + 1
if func then
if func(v, k, ...) then
count = count + 1
end
else
count = count + 1
end
end
return count, total
end
--- Returns an inverted (***{[value] = key,...}***) copy of the given table. If the values are not unique, the assigned key depends on the order of pairs().
-- @usage local a = {k1 = 'foo', k2 = 'bar'}
--table.invert(a) --returns {'foo' = k1, 'bar' = k2}
-- @usage local b = {k1 = 'foo', k2 = 'bar', k3 = 'bar'}
--table.invert(b) --returns {'foo' = k1, 'bar' = ?}
-- @tparam table tbl the table to invert
-- @treturn table a new table with inverted mapping
function table.invert(tbl)
local inverted = {}
for k, v in pairs(tbl) do
inverted[v] = k
end
return inverted
end
--- Return the size of a table using built in table_size function
-- @function size
-- @tparam table table to use
-- @treturn int size of the table
table.size = table_size
--- For all string or number values in an array map them to a key = true table
-- @usage local a = {"v1", "v2"}
-- table.array_to_dict_bool(a) -- return {["v1"] = true, ["v2"]= true}
-- @tparam table tbl the table to convert
-- @treturn table the converted table
function table.arr_to_bool(tbl)
local newtbl = {}
for _, v in pairs(tbl) do
if type(v) == "string" or type(v) == "number" then
newtbl[v] = true
end
end
return newtbl
end
-- Any thing below here i (cooldude2606) have added and was not here by default
--- Returns a value in a form able to be read as a value
-- @usage local a = 'value'
-- table.val_to_str(a) -- return '"value"'
-- @param v value to convert
-- @treturn string the converted value
function table.val_to_str(v)
if "string" == type( v ) then
v = string.gsub(v,"\n","\\n")
if string.match(string.gsub(v,"[^'\"]",""),'^"+$') then
return "'"..v.."'"
end
return '"'..string.gsub(v,'"', '\\"' )..'"'
else
return "table" == type( v) and table.to_string(v) or
"function" == type(v) and '"cant-display-function"' or
"userdata" == type(v) and '"cant-display-userdata"' or
tostring(v)
end
end
--- Returns a value in a form able to be read as a key
-- @usage local a = 'key'
-- table.key_to_str(a) -- return '["key"]'
-- @param k key to convert
-- @treturn string the converted key
function table.key_to_str (k)
if "string" == type(k) and string.match(k,"^[_%player][_%player%d]*$") then
return k
else
return "["..table.val_to_str(k).."]"
end
end
--- Returns a table in a form able to be read as a table
-- @usage local a = {k1='foo',k2='bar'}
-- table.tostring(a) -- return '{["k1"]="foo",["k2"]="bar"}'
-- @tparam table tbl table to convert
-- @treturn string the converted table
function table.to_string(tbl)
local result, done = {}, {}
for k, v in ipairs(tbl) do
table.insert(result,table.val_to_str(v))
done[k] = true
end
for k, v in pairs(tbl) do
if not done[k] then
table.insert(result,
table.key_to_str(k).."="..table.val_to_str(v))
end
end
return "{"..table.concat(result,",") .."}"
end
--- Simmilar to table.to_string but converts a lua table to a json one
-- @usage local a = {k1='foo',k2='bar'}
-- talbe.json(a) -- return '{"k1":"foo","k2":"bar"}'
-- @tparam table lua_table the table to convert
-- @treturn string the table in a json format
function table.json(lua_table)
local result, done, only_indexs = {}, {}, true
for key,value in ipairs(lua_table) do
done[key] = true
if type(value) == 'table' then table.insert(result,table.json(value,true))
elseif type(value) == 'string' then table.insert(result,'"'..value..'"')
elseif type(value) == 'number' then table.insert(result,value)
elseif type(value) == 'boolean' then table.insert(result,tostring(value))
else table.insert(result,'null')
end
end
for key,value in pairs(lua_table) do
if not done[key] then
only_indexs = false
if type(value) == 'table' then table.insert(result,'"'..key..'":'..table.json(value,true))
elseif type(value) == 'string' then table.insert(result,'"'..key..'":"'..value..'"')
elseif type(value) == 'number' then table.insert(result,'"'..key..'":'..value)
elseif type(value) == 'boolean' then table.insert(result,'"'..key..'":'..tostring(value))
else table.insert(result,'"'..key..'":null')
end
end
end
if only_indexs then return "["..table.concat(result,",").."]"
else return "{"..table.concat(result,",").."}"
end
end
--- Returns the closest match to a key
-- @usage tbl = {foo=1,bar=2}
-- table.autokey(tbl,'f') -- return 1
function table.autokey(tbl,str)
local _return = {}
for key,value in pairs(tbl) do
if string.contains(string.lower(key),string.lower(str)) then table.insert(_return,value) end
end
return _return[1] or false
end

31
StdLib/time.lua Normal file
View File

@@ -0,0 +1,31 @@
--- A defines module for retrieving the number of ticks in 1 unit of time.
-- Extends the Factorio defines table.
-- @module defines.time
-- @usage require('stdlib/defines/time')
-- defines table is automatically required in all mod loading stages.
-- luacheck: ignore 122/defines
-- Ignore assigning to read only defines table. defines table is not read only, however
-- marking it this way allows warnings to be generated when trying to assign values.
defines = defines or {} --luacheck: ignore defines (This is used for testing locally)
local SECOND = 60
local MINUTE = SECOND * 60
local HOUR = MINUTE * 60
local DAY = HOUR * 24
local WEEK = DAY * 7
local MONTH = DAY * 30
local YEAR = DAY * 365
--- Returns the number of ticks in a second, minute, hour, day, week, month, or year.
-- @usage local ten_seconds = defines.time.second * 10
defines.time = {
second = SECOND, -- the number of Factorio ticks in a second
minute = MINUTE, -- the number of Factorio ticks in a second
hour = HOUR, -- the number of Factorio ticks in an hour
day = DAY, -- the number of Factorio ticks in an day
week = WEEK, -- the number of Factorio ticks in a week
month = MONTH, -- the number of Factorio ticks in a month (30 days)
year = YEAR, -- the number of Factorio ticks in a year (365 days)
}