mirror of
https://github.com/PHIDIAS0303/ExpCluster.git
synced 2025-12-27 11:35:22 +09:00
Added command_auth_runtime_disable
This commit is contained in:
@@ -8,7 +8,7 @@ Commands.add_authenticator(function(player,command,tags,reject)
|
|||||||
if player.admin then
|
if player.admin then
|
||||||
return true
|
return true
|
||||||
else
|
else
|
||||||
return reject('This command is for admins only!')
|
return reject{'command-auth.admin-only'}
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
return true
|
return true
|
||||||
|
|||||||
25
config/command_auth_runtime_disable.lua
Normal file
25
config/command_auth_runtime_disable.lua
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
--- This config for command auth allows commands to be globally enabled and disabled during runtime
|
||||||
|
-- this config adds Commands.disable and Commands.enable to enable and disable commands for all users
|
||||||
|
local Commands = require 'expcore.commands'
|
||||||
|
local Global = require 'utils.global'
|
||||||
|
|
||||||
|
local disabled_commands = {}
|
||||||
|
Global.register(disabled_commands,function(tbl)
|
||||||
|
disabled_commands = tbl
|
||||||
|
end)
|
||||||
|
|
||||||
|
function Commands.disable(command_name)
|
||||||
|
disabled_commands[command_name] = true
|
||||||
|
end
|
||||||
|
|
||||||
|
function Commands.enable(command_name)
|
||||||
|
disabled_commands[command_name] = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
Commands.add_authenticator(function(player,command,tags,reject)
|
||||||
|
if disabled_commands[command] then
|
||||||
|
return reject{'command-auth.command-disabled'}
|
||||||
|
else
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end)
|
||||||
3
config/config.cfg
Normal file
3
config/config.cfg
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
[command-auth]
|
||||||
|
admin-only=This command is for (game) admins only!
|
||||||
|
command-disabled=This command has been disabled by management!
|
||||||
12
config/death_markers.lua
Normal file
12
config/death_markers.lua
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
--- This config controls what happens when a player dies mostly about map markers and item collection
|
||||||
|
-- allow_teleport_to_body_command and allow_collect_bodies_command can be over ridden if command_auth_runtime_disable is present
|
||||||
|
-- if not present then the commands will not be loaded into the game
|
||||||
|
return {
|
||||||
|
allow_teleport_to_body_command=false, -- allows use of /return-to-body which teleports you to your last death
|
||||||
|
allow_collect_bodies_command=false, -- allows use of /collect-body which returns all your items to you and removes the body
|
||||||
|
use_chests_as_bodies=false, -- weather items should be moved into a chest when a player dies
|
||||||
|
auto_collect_bodies=false, -- enables items being returned to the spawn point in chests upon death
|
||||||
|
show_map_markers=true, -- shows markers on the map where bodies are
|
||||||
|
include_time_of_death=true, -- weather to include the time of death on the map marker
|
||||||
|
map_icon='' -- the icon that the map marker shows '' means no icon
|
||||||
|
}
|
||||||
@@ -18,6 +18,7 @@ return {
|
|||||||
'modules.addons.chat-popups',
|
'modules.addons.chat-popups',
|
||||||
'modules.addons.damage-popups',
|
'modules.addons.damage-popups',
|
||||||
-- Config Files
|
-- Config Files
|
||||||
'config.command_auth_admin', -- commands tags with admin_only are blocked for non admins
|
'config.command_auth_admin', -- commands tagged with admin_only are blocked for non admins
|
||||||
|
'config.command_auth_runtime_disable', -- allows commands to be enabled and disabled during runtime
|
||||||
'config.permission_groups', -- loads some predefined permission groups
|
'config.permission_groups', -- loads some predefined permission groups
|
||||||
}
|
}
|
||||||
3
locale/en/config.cfg
Normal file
3
locale/en/config.cfg
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
[command-auth]
|
||||||
|
admin-only=This command is for (game) admins only!
|
||||||
|
command-disabled=This command has been disabled by management!
|
||||||
7
modules/addons/death-markers.lua
Normal file
7
modules/addons/death-markers.lua
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
local Event = require 'utils.event'
|
||||||
|
local Game = require 'utils.game'
|
||||||
|
local Global = require 'utils.global'
|
||||||
|
local Commands = require 'expcore.commands'
|
||||||
|
local config = require 'config.death_markers'
|
||||||
|
local opt_require = ext_require('expcore.common','opt_require')
|
||||||
|
opt_require 'config.command_auth_runtime_disable' -- if the file is present then we can disable the commands
|
||||||
@@ -1,330 +0,0 @@
|
|||||||
--- Adds some common functions used though out all ExpGaming modules
|
|
||||||
-- @module ExpGamingLib
|
|
||||||
-- @alias ExpLib
|
|
||||||
-- @author Cooldude2606
|
|
||||||
-- @license https://github.com/explosivegaming/scenario/blob/master/LICENSE
|
|
||||||
|
|
||||||
local Game = require('FactorioStdLib.Game')
|
|
||||||
local Color = require('FactorioStdLib.Color')
|
|
||||||
|
|
||||||
local module_verbose = false -- there is no verbose in this file so true will do nothing
|
|
||||||
local ExpLib = {}
|
|
||||||
|
|
||||||
--- Loads a table into _G even when sandboxes; will not overwrite values or append to tables; will not work during runtime to avoid desyncs
|
|
||||||
-- @usage unpack_to_G{key1='foo',key2='bar'}
|
|
||||||
-- @tparam table tbl table to be unpacked
|
|
||||||
function ExpLib.unpack_to_G(tbl)
|
|
||||||
if not type(tbl) == 'table' or game then return end
|
|
||||||
for key,value in pairs(tbl) do
|
|
||||||
if not _G[key] then rawset(_G,key,value) end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Used to get the current ENV with all _G keys removed; useful when saving function to global
|
|
||||||
-- @usage get_env() returns current ENV with _G keys removed
|
|
||||||
-- @treturn table the env table with _G keys removed
|
|
||||||
-- @warning does not work from console
|
|
||||||
function ExpLib.get_env(level)
|
|
||||||
level = level and level+1 or 2
|
|
||||||
local env = setmetatable({},{__index=_G})
|
|
||||||
while true do
|
|
||||||
if not debug.getinfo(level) then break end
|
|
||||||
local i = 1
|
|
||||||
while true do
|
|
||||||
local name, value = debug.getlocal(level,i)
|
|
||||||
if not name or _G[name] == value then break else env[name] = value end
|
|
||||||
i=i+1
|
|
||||||
end
|
|
||||||
level=level+1
|
|
||||||
end
|
|
||||||
return env
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Used to get the current ENV with all _G keys removed; useful when saving function to global
|
|
||||||
-- @usage get_env() returns current ENV with _G keys removed
|
|
||||||
-- @treturn table the env table with _G keys removed
|
|
||||||
-- @warning does not work from console
|
|
||||||
function ExpLib.get_upvalues(level)
|
|
||||||
local func = level and ExpLib.is_type(level,'function') and level or nil
|
|
||||||
level = level and ExpLib.is_type(level,'number') and level+1 or 2
|
|
||||||
func = func or debug.getinfo(level).func
|
|
||||||
local upvalues = setmetatable({},{__index=_G})
|
|
||||||
local i = 1
|
|
||||||
while true do
|
|
||||||
local name, value = debug.getupvalue(func,i)
|
|
||||||
if not name then break else upvalues[name] = value end
|
|
||||||
i=i+1
|
|
||||||
end
|
|
||||||
return upvalues
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Creates a table that will act like a string and a function
|
|
||||||
-- @usage add_metatable({},function) -- returns table
|
|
||||||
-- @tparam table tbl the table that will have its metatable set
|
|
||||||
-- @tparam[opt=tostring] function callback the function that will be used for the call
|
|
||||||
-- @tparam[opt=table.tostring] ?function|string string a function that resolves to a string or a string
|
|
||||||
-- @treturn table the new table with its metatable set
|
|
||||||
function ExpLib.add_metatable(tbl,callback,string)
|
|
||||||
if not ExpLib.is_type(tbl,'table') then error('No table given to add_metatable',2) end
|
|
||||||
callback = ExpLib.is_type(callback,'function') and callback or tostring
|
|
||||||
string = ExpLib.is_type(string,'function') and string or ExpLib.is_type(string,'string') and function() return string end or table.tostring
|
|
||||||
return setmetatable(tbl,{
|
|
||||||
__tostring=string,
|
|
||||||
__concat=function(val1,val2) return type(val1) == 'string' and val1..string(val2) or string(val1)..val2 end,
|
|
||||||
__call=callback
|
|
||||||
})
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Compare types faster for faster validation of prams
|
|
||||||
-- @usage is_type('foo','string') -- return true
|
|
||||||
-- @usage is_type('foo') -- return false
|
|
||||||
-- @param v 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 ExpLib.is_type(v,test_type)
|
|
||||||
return test_type and v and type(v) == test_type or not test_type and not v or false
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Compare types faster for faster validation of prams, including giving an error if incorrect
|
|
||||||
-- @usage type_error('foo','string','Value is not a string') -- return true
|
|
||||||
-- @usage type_error('foo','table','Value is not a string') -- return error
|
|
||||||
-- @param value the value to be tested
|
|
||||||
-- @tparam[opt=nil] string type the type that the value should be
|
|
||||||
-- @tparam string error_message the message given when type is not matched
|
|
||||||
-- @treturn boolean if it matched or and error
|
|
||||||
function ExpLib.type_error(value,type,error_message)
|
|
||||||
return ExpLib.is_type(value,type) or error(error_message,3)
|
|
||||||
end
|
|
||||||
|
|
||||||
--- A specialised version of type_error to test for self
|
|
||||||
-- @usage self_test(self,'Object','get_name')
|
|
||||||
-- @tparam table self the table that is the object
|
|
||||||
-- @tparam string prototype_name the name of the class
|
|
||||||
-- @tparam string function_name the name of the function
|
|
||||||
function ExpLib.self_test(self,prototype_name,function_name)
|
|
||||||
return ExpLib.is_type(self,'table') or error('Call to prototype without context, either supply a '..prototype_name..' or use '..prototype_name..':'..function_name,3)
|
|
||||||
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
|
|
||||||
-- @usage player_return('Hello, World!',nil,player) -- returns 'Hello, World!' to the given player
|
|
||||||
-- @param rtn any value of any type that will be returned to the player or console
|
|
||||||
-- @tparam[opt=defines.colour.white] ?defines.color|string colour the colour of the text for the player, ignored when printing to console
|
|
||||||
-- @tparam[opt=game.player] LuaPlayer player the player that return will go to, if no game.player then returns to server
|
|
||||||
function ExpLib.player_return(rtn,colour,player)
|
|
||||||
colour = ExpLib.is_type(colour,'table') and colour or defines.textcolor[colour] ~= defines.color.white and defines.textcolor[colour] or defines.color[colour]
|
|
||||||
player = player or game.player
|
|
||||||
-- converts the value to a string
|
|
||||||
local returnAsString
|
|
||||||
if ExpLib.is_type(rtn,'table') then
|
|
||||||
if ExpLib.is_type(rtn.__self,'userdata') then
|
|
||||||
-- value is userdata
|
|
||||||
returnAsString = 'Cant Display Userdata'
|
|
||||||
elseif ExpLib.is_type(rtn[1],'string') and string.find(rtn[1],'.+[.].+') and not string.find(rtn[1],'%s') then
|
|
||||||
-- value is a locale string
|
|
||||||
returnAsString = rtn
|
|
||||||
elseif getmetatable(rtn) ~= nil and not tostring(rtn):find('table: 0x') then
|
|
||||||
-- value has a tostring meta method
|
|
||||||
returnAsString = tostring(rtn)
|
|
||||||
else
|
|
||||||
-- value is a table
|
|
||||||
returnAsString = table.tostring(rtn)
|
|
||||||
end
|
|
||||||
elseif ExpLib.is_type(rtn,'function') then
|
|
||||||
-- value is a function
|
|
||||||
returnAsString = 'Cant Display Functions'
|
|
||||||
else returnAsString = tostring(rtn) end
|
|
||||||
-- returns to the player or the server
|
|
||||||
if player then
|
|
||||||
-- allows any valid player identifier to be used
|
|
||||||
player = Game.get_player(player)
|
|
||||||
if not player then error('Invalid Player given to player_return',2) end
|
|
||||||
-- plays a nice sound that is different to normal message sound
|
|
||||||
player.play_sound{path='utility/scenario_message'}
|
|
||||||
player.print(returnAsString,colour)
|
|
||||||
else rcon.print(returnAsString) end
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Convert ticks to hours
|
|
||||||
-- @usage tick_to_hour(216001) -- return 1
|
|
||||||
-- @tparam number tick tick to convert to hours
|
|
||||||
-- @treturn number the number of whole hours from this tick
|
|
||||||
function ExpLib.tick_to_hour(tick)
|
|
||||||
if not ExpLib.is_type(tick,'number') then return 0 end
|
|
||||||
if not game then return math.floor(tick/216000) end
|
|
||||||
return math.floor(tick/(216000*game.speed))
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Convert ticks to minutes
|
|
||||||
-- @usage tick_to_hour(3601) -- return 1
|
|
||||||
-- @tparam number tick tick to convert to minutes
|
|
||||||
-- @treturn number the number of whole minutes from this tick
|
|
||||||
function ExpLib.tick_to_min (tick)
|
|
||||||
if not ExpLib.is_type(tick,'number') then return 0 end
|
|
||||||
if not game then return math.floor(tick/3600) end
|
|
||||||
return math.floor(tick/(3600*game.speed))
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Converts a tick into a clean format for end user
|
|
||||||
-- @usage tick_to_display_format(3600) -- return '1.00 M'
|
|
||||||
-- @usage tick_to_display_format(234000) -- return '1 H 5 M'
|
|
||||||
-- @tparam number tick the tick to convert
|
|
||||||
-- @treturn string the formated string
|
|
||||||
function ExpLib.tick_to_display_format(tick)
|
|
||||||
if not ExpLib.is_type(tick,'number') then return '0H 0M' end
|
|
||||||
if ExpLib.tick_to_min(tick) < 10 then
|
|
||||||
if not game then return math.floor(tick/3600) end
|
|
||||||
return string.format('%.2f M',tick/(3600*game.speed))
|
|
||||||
else
|
|
||||||
return string.format('%d H %d M',
|
|
||||||
ExpLib.tick_to_hour(tick),
|
|
||||||
ExpLib.tick_to_min(tick)-60*ExpLib.tick_to_hour(tick)
|
|
||||||
)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Used as a way to view the structure of a gui, used for debugging
|
|
||||||
-- @usage Gui_tree(root) returns all children of gui recursively
|
|
||||||
-- @tparam LuaGuiElement root the root to start the tree from
|
|
||||||
-- @treturn table the table that describes the gui
|
|
||||||
function ExpLib.gui_tree(root)
|
|
||||||
if not ExpLib.is_type(root,'table') or not root.valid then error('Invalid Gui Element given to gui_tree',2) end
|
|
||||||
local tree = {}
|
|
||||||
for _,child in pairs(root.children) do
|
|
||||||
if #child.children > 0 then
|
|
||||||
if child.name then tree[child.name] = ExpLib.gui_tree(child)
|
|
||||||
else table.insert(tree,ExpLib.gui_tree(child)) end
|
|
||||||
else
|
|
||||||
if child.name then tree[child.name] = child.type
|
|
||||||
else table.insert(tree,child.type) end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return tree
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Extents the table class
|
|
||||||
-- @type table
|
|
||||||
-- @alias table
|
|
||||||
|
|
||||||
--- Returns a value in a form able to be read as a value, any value to string
|
|
||||||
-- @usage table.val_to_str{a='foo'} -- return '"foo"'
|
|
||||||
-- @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.tostring(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, any key to string
|
|
||||||
-- @usage table.val_to_str{a='foo'} -- return '["a"]'
|
|
||||||
-- @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 table.tostring{k1='foo',k2='bar'} -- return '{["k1"]="foo",["k2"]="bar"}'
|
|
||||||
-- @tparam table tbl table to convert
|
|
||||||
-- @treturn string the converted table
|
|
||||||
function table.tostring(tbl)
|
|
||||||
if type(tbl) ~= 'table' then return tostring(tbl) end
|
|
||||||
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
|
|
||||||
|
|
||||||
--- Similar to table.tostring but converts a lua table to a json one
|
|
||||||
-- @usage table.json{k1='foo',k2='bar'} -- 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)
|
|
||||||
--if game and game.table_to_json then return game.table_to_json(lua_table) end
|
|
||||||
local result, done, only_indexes = {}, {}, 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 not value then table.insert(result,'null')
|
|
||||||
else table.insert(result,table.val_to_str(value))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
for key,value in pairs(lua_table) do
|
|
||||||
if not done[key] then
|
|
||||||
only_indexes = false
|
|
||||||
if type(value) == 'table' then table.insert(result,table.val_to_str(key)..':'..table.json(value,true))
|
|
||||||
elseif not value then table.insert(result,table.val_to_str(key)..':null')
|
|
||||||
else table.insert(result,table.val_to_str(key)..':'..table.val_to_str(value))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if only_indexes then return "["..table.concat(result,",").."]"
|
|
||||||
else return "{"..table.concat(result,",").."}"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Returns the closest match to a key
|
|
||||||
-- @usage table.autokey({foo=1,bar=2},'f') -- return 1
|
|
||||||
-- @tparam table tbl the table that will be searched
|
|
||||||
-- @tparam string str the string that will be looked for in the keys
|
|
||||||
function table.autokey(tbl,str)
|
|
||||||
if not ExpLib.is_type(str,'string') then return end
|
|
||||||
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
|
|
||||||
|
|
||||||
--- Returns the list is a sorted way that would be expected by people (this is by key)
|
|
||||||
-- @usage tbl = table.alphanumsort(tbl)
|
|
||||||
-- @tparam table tbl the table to be sorted
|
|
||||||
-- @treturn table the sorted table
|
|
||||||
function table.alphanumsort(tbl)
|
|
||||||
local o = 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 alterative than above)
|
|
||||||
-- @usage tbl = table.alphanumsort(tbl)
|
|
||||||
-- @tparam table tbl the table to be sorted
|
|
||||||
-- @treturn table the sorted table
|
|
||||||
function table.keysort(tbl)
|
|
||||||
local o = table.keys(tbl,true)
|
|
||||||
local _tbl = {}
|
|
||||||
for _,k in pairs(o) do _tbl[k] = tbl[k] end
|
|
||||||
return _tbl
|
|
||||||
end
|
|
||||||
|
|
||||||
ExpLib:unpack_to_G()
|
|
||||||
return ExpLib
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "ExpGamingLib",
|
|
||||||
"version": "4.0.0",
|
|
||||||
"description": "Adds some common functions used though out all ExpGaming modules",
|
|
||||||
"location": "FSM_ARCHIVE",
|
|
||||||
"keywords": [
|
|
||||||
"ExpGaming",
|
|
||||||
"Lib"
|
|
||||||
],
|
|
||||||
"author": "Cooldude2606",
|
|
||||||
"contact": "Discord: Cooldude2606#5241",
|
|
||||||
"license": "https://github.com/explosivegaming/scenario/blob/master/LICENSE",
|
|
||||||
"dependencies": {
|
|
||||||
"FactorioStdLib.Game": "^0.8.0",
|
|
||||||
"FactorioStdLib.Color": "^0.8.0",
|
|
||||||
"FactorioStdLib.Table": "^0.8.0"
|
|
||||||
},
|
|
||||||
"submodules": {}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user