508 lines
14 KiB
Lua
508 lines
14 KiB
Lua
local this = {}
|
|
local util = scripts.util
|
|
local metatables = scripts.metatables
|
|
|
|
local type, rawget, rawset, pairs, ipairs = type, rawget, rawset, pairs, ipairs
|
|
|
|
|
|
function this.on_scripts_initialized()
|
|
require("scripts.helpers.LuaControl")
|
|
require("scripts.helpers.LuaEntity")
|
|
require("scripts.helpers.LuaItemPrototype")
|
|
require("scripts.helpers.LuaPlayer")
|
|
require("scripts.helpers.LuaRecipe")
|
|
require("scripts.helpers.Position")
|
|
require("scripts.helpers.BoundingBox")
|
|
end
|
|
|
|
|
|
metatables.helpers = {
|
|
__index = function(t, k)
|
|
return this[k] or rawget(t, "__on")[k]
|
|
end,
|
|
__newindex = function(t, k, v)
|
|
rawget(t, "__on")[k] = v
|
|
end,
|
|
__len = function(t)
|
|
return #rawget(t, "__on")
|
|
end,
|
|
}
|
|
|
|
function this.on(obj) -- wraps object in table with helper methods
|
|
if type(obj) == "table" and not obj.__self and rawget(obj, "__on") then -- reapply metatable
|
|
return metatables.use(obj, "helpers")
|
|
else -- new metatable
|
|
return metatables.use({ __on = obj }, "helpers")
|
|
end
|
|
end
|
|
local _ = this.on
|
|
|
|
function this:toPlain()
|
|
return rawget(self, "__on")
|
|
end
|
|
|
|
local conditions = {
|
|
["nil"] = function(obj) return obj == nil end,
|
|
["any"] = function(obj) return obj ~= nil end,
|
|
["string"] = function(obj) return type(obj) == "string" end,
|
|
["number"] = function(obj) return type(obj) == "number" end,
|
|
["table"] = function(obj) return type(obj) == "table" end,
|
|
["object"] = function(obj) return type(obj) == "table" and obj.__self end,
|
|
["empty"] = util.isEmpty,
|
|
["filled"] = util.isFilled,
|
|
["valid"] = util.isValid,
|
|
["valid stack"] = util.isValidStack,
|
|
["valid player"] = util.isValidPlayer,
|
|
|
|
-- Custom type conditions
|
|
["crafting machine"] = util.isCraftingMachine,
|
|
["fuel"] = function(obj) return obj.object_name == "LuaItemStack" and obj.prototype.fuel_category ~= nil or obj.fuel_category ~= nil end,
|
|
["ammo"] = function(obj) return obj.type == "ammo" end,
|
|
}
|
|
|
|
local function applyNot(notModeActive, value)
|
|
if notModeActive then
|
|
return not value
|
|
else
|
|
return value
|
|
end
|
|
end
|
|
|
|
function this:is(...)
|
|
local isargs = {...}
|
|
local obj = rawget(self, "__on")
|
|
local notModeActive = false
|
|
local result = true
|
|
|
|
for __,condition in ipairs(isargs) do
|
|
|
|
if condition == "not" then
|
|
notModeActive = not notModeActive -- toggle notModeActive
|
|
|
|
else
|
|
if type(condition) == "table" then -- custom field check
|
|
local value = obj
|
|
for __,key in ipairs(condition) do
|
|
value = value[key]
|
|
end
|
|
|
|
local nestedIs = condition.is or condition.isnot -- nested Is check on custom field
|
|
if condition.is ~= nil then
|
|
value = type(nestedIs) == "table" and _(value):is(unpack(nestedIs)) or _(value):is(nestedIs)
|
|
elseif condition.isnot ~= nil then
|
|
value = type(nestedIs) == "table" and _(value):isnot(unpack(nestedIs)) or _(value):isnot(nestedIs)
|
|
end
|
|
|
|
result = result and applyNot(notModeActive, value)
|
|
|
|
elseif type(condition) == "function" then -- custom function
|
|
result = result and applyNot(notModeActive, condition(obj))
|
|
|
|
elseif conditions[condition] then -- normal condition check
|
|
result = result and applyNot(notModeActive, conditions[condition](obj))
|
|
|
|
else -- direct value check
|
|
result = result and applyNot(notModeActive, obj == condition)
|
|
end
|
|
notModeActive = false
|
|
|
|
-- early return if condition unmet
|
|
if not result then return result end
|
|
end
|
|
end
|
|
|
|
return result
|
|
end
|
|
|
|
function this:isnot(...)
|
|
local isargs = {...}
|
|
local obj = rawget(self, "__on")
|
|
local notModeActive = false
|
|
local result = true
|
|
|
|
for __,condition in ipairs(isargs) do
|
|
|
|
if condition == "not" then
|
|
notModeActive = not notModeActive -- toggle notModeActive
|
|
|
|
else
|
|
if type(condition) == "table" then -- custom field check
|
|
local value = obj
|
|
for __,key in ipairs(condition) do
|
|
value = value[key]
|
|
end
|
|
|
|
local nestedIs = condition.is or condition.isnot -- nested Is check on custom field
|
|
if condition.is ~= nil then
|
|
value = type(nestedIs) == "table" and _(value):is(unpack(nestedIs)) or _(value):is(nestedIs)
|
|
elseif condition.isnot ~= nil then
|
|
value = type(nestedIs) == "table" and _(value):isnot(unpack(nestedIs)) or _(value):isnot(nestedIs)
|
|
end
|
|
|
|
result = result and applyNot(notModeActive, value)
|
|
|
|
elseif type(condition) == "function" then -- custom function
|
|
result = result and applyNot(notModeActive, condition(obj))
|
|
|
|
elseif conditions[condition] then -- normal condition check
|
|
result = result and applyNot(notModeActive, conditions[condition](obj))
|
|
|
|
else -- direct value check
|
|
result = result and applyNot(notModeActive, obj == condition)
|
|
end
|
|
notModeActive = false
|
|
|
|
-- early return if condition unmet
|
|
if not result then return not result end
|
|
end
|
|
end
|
|
|
|
return not result
|
|
end
|
|
|
|
function this:has(condition, ...)
|
|
return self:is({is=condition, ...})
|
|
end
|
|
|
|
function this:hasnot(condition, ...)
|
|
return self:isnot({is=condition, ...})
|
|
end
|
|
|
|
function this:each(func)
|
|
local obj = rawget(self, "__on")
|
|
local iter = metatables.uses(obj, "entityAsIndex") and util.epairs or pairs
|
|
|
|
for k,v in iter(obj) do
|
|
func(k, v)
|
|
end
|
|
|
|
return self
|
|
end
|
|
|
|
function this:where(...)
|
|
local args = {...}
|
|
local func = args[#args]
|
|
local obj = rawget(self, "__on")
|
|
local iter = metatables.uses(obj, "entityAsIndex") and util.epairs or pairs
|
|
|
|
-- user passed anonymouse iterator function to where() directly (as last argument)
|
|
if #args > 1 and type(func) == "function" then
|
|
args[#args] = nil
|
|
|
|
for k,v in iter(obj) do
|
|
if _(v or k):is(unpack(args)) then
|
|
func(k, v)
|
|
end
|
|
end
|
|
|
|
return self
|
|
|
|
else -- or only filter out results and return table
|
|
local result = {}
|
|
|
|
for k,v in iter(obj) do
|
|
if _(v or k):is(...) then
|
|
result[k] = v
|
|
end
|
|
end
|
|
|
|
return _(result)
|
|
end
|
|
end
|
|
|
|
function this:unless(...) -- wherenot
|
|
local args = {...}
|
|
local func = args[#args]
|
|
local obj = rawget(self, "__on")
|
|
local iter = metatables.uses(obj, "entityAsIndex") and util.epairs or pairs
|
|
|
|
if #args > 1 and type(func) == "function" then -- if user passed anonymouse function to where() directly (as last argument)
|
|
args[#args] = nil
|
|
|
|
for k,v in iter(obj) do
|
|
if _(v or k):isnot(unpack(args)) then
|
|
func(k, v)
|
|
end
|
|
end
|
|
|
|
return self
|
|
|
|
else -- else only filter out results
|
|
local result = {}
|
|
|
|
for k,v in iter(obj) do
|
|
if _(v or k):isnot(...) then
|
|
result[k] = v
|
|
end
|
|
end
|
|
|
|
return _(result)
|
|
end
|
|
end
|
|
|
|
function this:wherekey(...)
|
|
local args = {...}
|
|
local func = args[#args]
|
|
local obj = rawget(self, "__on")
|
|
local iter = metatables.uses(obj, "entityAsIndex") and util.epairs or pairs
|
|
|
|
-- user passed anonymouse iterator function to where() directly (as last argument)
|
|
if #args > 1 and type(func) == "function" then
|
|
args[#args] = nil
|
|
|
|
for k,v in iter(obj) do
|
|
if _(k):is(unpack(args)) then
|
|
func(k, v)
|
|
end
|
|
end
|
|
|
|
return self
|
|
|
|
else -- or only filter out results and return table
|
|
local result = {}
|
|
|
|
for k,v in iter(obj) do
|
|
if _(k):is(...) then
|
|
result[k] = v
|
|
end
|
|
end
|
|
|
|
return _(result)
|
|
end
|
|
end
|
|
|
|
function this:unlesskey(...) -- wherenot
|
|
local args = {...}
|
|
local func = args[#args]
|
|
local obj = rawget(self, "__on")
|
|
local iter = metatables.uses(obj, "entityAsIndex") and util.epairs or pairs
|
|
|
|
if #args > 1 and type(func) == "function" then -- if user passed anonymouse function to where() directly (as last argument)
|
|
args[#args] = nil
|
|
|
|
for k,v in iter(obj) do
|
|
if _(k):isnot(unpack(args)) then
|
|
func(k, v)
|
|
end
|
|
end
|
|
|
|
return self
|
|
|
|
else -- else only filter out results
|
|
local result = {}
|
|
|
|
for k,v in iter(obj) do
|
|
if _(k):isnot(...) then
|
|
result[k] = v
|
|
end
|
|
end
|
|
|
|
return _(result)
|
|
end
|
|
end
|
|
|
|
function this:wherepair(...)
|
|
local args = {...}
|
|
local func = args[#args]
|
|
local obj = rawget(self, "__on")
|
|
local iter = metatables.uses(obj, "entityAsIndex") and util.epairs or pairs
|
|
|
|
-- user passed anonymouse iterator function to where() directly (as last argument)
|
|
if #args > 1 and type(func) == "function" then
|
|
args[#args] = nil
|
|
|
|
for k,v in iter(obj) do
|
|
if _({k,v}):is(unpack(args)) then
|
|
func(k, v)
|
|
end
|
|
end
|
|
|
|
return self
|
|
|
|
else -- or only filter out results and return table
|
|
local result = {}
|
|
|
|
for k,v in iter(obj) do
|
|
if _({k,v}):is(...) then
|
|
result[k] = v
|
|
end
|
|
end
|
|
|
|
return _(result)
|
|
end
|
|
end
|
|
|
|
function this:unlesspair(...) -- wherenot
|
|
local args = {...}
|
|
local func = args[#args]
|
|
local obj = rawget(self, "__on")
|
|
local iter = metatables.uses(obj, "entityAsIndex") and util.epairs or pairs
|
|
|
|
if #args > 1 and type(func) == "function" then -- if user passed anonymouse function to where() directly (as last argument)
|
|
args[#args] = nil
|
|
|
|
for k,v in iter(obj) do
|
|
if _({k,v}):isnot(unpack(args)) then
|
|
func(k, v)
|
|
end
|
|
end
|
|
|
|
return self
|
|
|
|
else -- else only filter out results
|
|
local result = {}
|
|
|
|
for k,v in iter(obj) do
|
|
if _({k,v}):isnot(...) then
|
|
result[k] = v
|
|
end
|
|
end
|
|
|
|
return _(result)
|
|
end
|
|
end
|
|
|
|
function this:wherehas(condition, ...)
|
|
local args = {...}
|
|
local count = #args
|
|
local func = args[count]
|
|
args.is = condition
|
|
|
|
if count > 1 and type(func) == "function" then
|
|
args[count] = nil
|
|
return self:where(args, func)
|
|
else
|
|
return self:where(args)
|
|
end
|
|
end
|
|
|
|
function this:unlesshas(condition, ...)
|
|
local args = {...}
|
|
local count = #args
|
|
local func = args[count]
|
|
args.is = condition
|
|
|
|
if count > 1 and type(func) == "function" then
|
|
args[count] = nil
|
|
return self:unless(args, func)
|
|
else
|
|
return self:unless(args)
|
|
end
|
|
end
|
|
|
|
function this:contains(value) -- table contains value
|
|
local obj = rawget(self, "__on")
|
|
local iter = metatables.uses(obj, "entityAsIndex") and util.epairs or pairs
|
|
|
|
for k,v in iter(obj) do
|
|
if v == value then
|
|
return true
|
|
end
|
|
end
|
|
|
|
return false
|
|
end
|
|
|
|
function this:set(values)
|
|
local obj = rawget(self, "__on")
|
|
values = rawget(values, "__on") or values
|
|
|
|
for k,v in pairs(values) do
|
|
obj[k] = v
|
|
end
|
|
|
|
return self
|
|
end
|
|
|
|
function this:map(func)
|
|
local obj = rawget(self, "__on")
|
|
local iter = metatables.uses(obj, "entityAsIndex") and util.epairs or pairs
|
|
local result = {}
|
|
|
|
for k,v in iter(obj) do
|
|
local k2,v2 = func(k,v)
|
|
if k2 == nil then
|
|
result[#result + 1] = v2
|
|
else
|
|
result[k2] = v2
|
|
end
|
|
end
|
|
|
|
return _(result)
|
|
end
|
|
|
|
function this:toArray()
|
|
return self:map(function(k,v)
|
|
return nil, v
|
|
end)
|
|
end
|
|
|
|
function this:keys()
|
|
return self:map(function(k)
|
|
return nil, k
|
|
end)
|
|
end
|
|
|
|
function this:sort(...)
|
|
local obj = rawget(self, "__on")
|
|
|
|
table.sort(obj, ...)
|
|
|
|
return self
|
|
end
|
|
|
|
function this:sum(key)
|
|
local obj = rawget(self, "__on")
|
|
local iter = metatables.uses(obj, "entityAsIndex") and util.epairs or pairs
|
|
local result = 0
|
|
|
|
if type(key) == "function" then
|
|
for k,v in iter(obj) do
|
|
result = result + key(k,v)
|
|
end
|
|
|
|
else
|
|
for k,v in iter(obj) do
|
|
result = result + v[key]
|
|
end
|
|
end
|
|
|
|
return result
|
|
end
|
|
|
|
function this:groupBy(key)
|
|
local obj = rawget(self, "__on")
|
|
local iter = metatables.uses(obj, "entityAsIndex") and util.epairs or pairs
|
|
local result = {}
|
|
|
|
if type(key) == "function" then
|
|
for k,v in iter(obj) do
|
|
local value = key(k,v)
|
|
if value ~= nil then
|
|
result[value] = result[value] or {}
|
|
if type(k) == "number" then
|
|
result[value][#result[value] + 1] = v
|
|
else
|
|
result[value][k] = v
|
|
end
|
|
end
|
|
end
|
|
|
|
else
|
|
for k,v in iter(obj) do
|
|
local value = v[key]
|
|
if value ~= nil then
|
|
result[value] = result[value] or {}
|
|
if type(k) == "number" then
|
|
result[value][#result[value] + 1] = v
|
|
else
|
|
result[value][k] = v
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
return _(result)
|
|
end
|
|
|
|
return this |