mirror of
https://github.com/PHIDIAS0303/ExpCluster.git
synced 2025-12-27 03:25:23 +09:00
Module: ExpGamingLib
This commit is contained in:
126
ExpLib.lua
126
ExpLib.lua
@@ -1,126 +0,0 @@
|
||||
--[[
|
||||
Explosive Gaming
|
||||
|
||||
This file can be used with permission but this and the credit below must remain in the file.
|
||||
Contact a member of management on our discord to seek permission to use our code.
|
||||
Any changes that you may make to the code are yours but that does not make the script yours.
|
||||
Discord: https://discord.gg/r6dC2uK
|
||||
]]
|
||||
--Please Only Edit Below This Line-----------------------------------------------------------
|
||||
|
||||
-- @module ExpLib
|
||||
-- @usage require('/ExpLib')
|
||||
|
||||
local ExpLib = {}
|
||||
--- Loads a table into the global lua table
|
||||
-- @usage a = {k1='foo',k2='bar'}
|
||||
-- _load_to_G(a)
|
||||
-- @tparam table tbl table to add to the global lua table
|
||||
function ExpLib._unpack_to_G(tbl)
|
||||
if not type(tbl) == 'table' or game then return end
|
||||
for name,value in pairs(tbl) do
|
||||
if not _G[name] then _G[name] = value end
|
||||
end
|
||||
end
|
||||
|
||||
--- Returns a bolean based on the type of v matching the test type
|
||||
-- @usage a = 'foo'
|
||||
-- is_type(a,'string') -- return true
|
||||
-- @param v the value to be tested
|
||||
-- @tparam[opt=nil] string test_type the type to test for if nil then it tests for nil
|
||||
-- @treturn bolean is v a matching 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
|
||||
|
||||
--- Returns a value to the player or if no player then log the return
|
||||
-- @usage a = 'to return'
|
||||
-- player_return(a)
|
||||
-- @param rtn the value to return
|
||||
-- @param player the player to print to
|
||||
function ExpLib.player_return(rtn,colour,player)
|
||||
local colour = colour or defines.color.white
|
||||
local player = player or game.player
|
||||
if player then
|
||||
local player = Game.get_player(player)
|
||||
if not player then return end
|
||||
player.play_sound{path='utility/scenario_message'}
|
||||
if is_type(rtn,'table') then
|
||||
-- test if its a localised string
|
||||
if is_type(rtn.__self,'userdata') then player.print('Cant Display Userdata',colour)
|
||||
elseif is_type(rtn[1],'string') and string.find(rtn[1],'.+[.].+') and not string.find(rtn[1],'%s') then pcall(player.print,rtn,colour)
|
||||
else player.print(table.to_string(rtn),colour)
|
||||
end
|
||||
elseif is_type(rtn,'function') then player.print('Cant Display Functions',colour)
|
||||
else player.print(tostring(rtn),colour)
|
||||
end
|
||||
else
|
||||
local _return = 'Invalid'
|
||||
if is_type(rtn,'table') then _return = table.to_string(rtn)
|
||||
elseif is_type(rtn,'function') then _return = 'Cant Display Functions'
|
||||
elseif is_type(rtn,'userdata') then _return = 'Cant Display Userdata'
|
||||
else _return = tostring(rtn)
|
||||
end log(_return) rcon.print(_return)
|
||||
end
|
||||
end
|
||||
|
||||
--- Convert ticks to hours
|
||||
-- @usage a = 216001
|
||||
-- tick_to_hour(a) -- return 1
|
||||
-- @tparam number tick to convert to hours
|
||||
-- @treturn number the number of whole hours from this tick
|
||||
function ExpLib.tick_to_hour(tick)
|
||||
if not is_type(tick,'number') then return 0 end
|
||||
return math.floor(tick/(216000*game.speed))
|
||||
end
|
||||
|
||||
--- Convert ticks to minutes
|
||||
-- @usage a = 3601
|
||||
-- tick_to_hour(a) -- return 1
|
||||
-- @tparam number tick to convert to minutes
|
||||
-- @treturn number the number of whole minutes from this tick
|
||||
function ExpLib.tick_to_min (tick)
|
||||
if not is_type(tick,'number') then return 0 end
|
||||
return math.floor(tick/(3600*game.speed))
|
||||
end
|
||||
|
||||
--- Returns a tick in a displayable format
|
||||
-- @usage a = 3600
|
||||
-- tick_to_display_format(a) -- return '1.00 M'
|
||||
-- @usage a = 234000
|
||||
-- tick_to_display_format(a) -- return '1 H 5 M'
|
||||
-- @tparam number tick to convert
|
||||
-- @treturn string the formated string
|
||||
function ExpLib.tick_to_display_format(tick)
|
||||
if not is_type(tick,'number') then return '0H 0M' end
|
||||
if tick_to_min(tick) < 10 then
|
||||
return string.format('%.2f M',tick/(3600*game.speed))
|
||||
else
|
||||
return string.format('%d H %d M',
|
||||
tick_to_hour(tick),
|
||||
tick_to_min(tick)-60*tick_to_hour(tick)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
function ExpLib.Gui_tree(root)
|
||||
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
|
||||
|
||||
return ExpLib
|
||||
474
FactorioSoftmodManager.lua
Normal file
474
FactorioSoftmodManager.lua
Normal file
@@ -0,0 +1,474 @@
|
||||
-- Used to load all other modules that are indexed in index.lua
|
||||
local moduleIndex = require("/modules/index")
|
||||
local Manager = {}
|
||||
--- Setup for metatable of the Manager to force read only nature
|
||||
-- @usage Manager() -- runs Manager.loadModdules()
|
||||
-- @usage Manager[name] -- returns module by that name
|
||||
-- @usage tostring(Manager) -- returns formated list of loaded modules
|
||||
local ReadOnlyManager = setmetatable({},{
|
||||
__metatable=false,
|
||||
__index=function(tbl,key)
|
||||
-- first looks in manager and then looks in mander.loadModules
|
||||
return rawget(Manager,key) ~= nil and rawget(Manager,key) or rawget(Manager.loadModules,key)
|
||||
end,
|
||||
__call=function(tbl)
|
||||
-- if there are no modules loaded then it loads them
|
||||
if #tbl.loadModules == 0 then
|
||||
tbl.loadModules()
|
||||
end
|
||||
end,
|
||||
__newindex=function(tbl,key,value)
|
||||
-- provents the changing of any key that is not currentState
|
||||
if key == 'currentState' then
|
||||
-- provides a verbose that is always emited describing the change in state
|
||||
Manager.verbose('Current state is now: "'..value.. '"; The verbose state is now: '..tostring(Manager.setVerbose[value]),true)
|
||||
rawset(Manager,key,value)
|
||||
else error('Manager is read only please use included methods',2) end
|
||||
end,
|
||||
__tostring=function(tbl)
|
||||
-- acts as a redirect
|
||||
return tostring(Manager.loadModules)
|
||||
end
|
||||
})
|
||||
local function setupModuleName(name)
|
||||
-- creates a table that acts like a string but is read only
|
||||
return setmetatable({},{
|
||||
__index=function(tbl,key) return name end,
|
||||
__newindex=function(tbl,key,value) error('Module Name Is Read Only') end,
|
||||
__tostring=function(tbl) return name end,
|
||||
__concat=function(val1,val2) return type(val1) == 'string' and val1..name or name..val2 end,
|
||||
__metatable=false,
|
||||
})
|
||||
end
|
||||
|
||||
Manager.currentState = 'selfInit'
|
||||
-- selfInit > moduleLoad > moduleInit > moduleEnv
|
||||
|
||||
--- Default output for the verbose
|
||||
-- @usage Manager.verbose('Hello, World!')
|
||||
-- @tparm rtn string the value that will be returned though verbose output
|
||||
Manager._verbose = function(rtn)
|
||||
-- creates one file per game, ie clears file on reset
|
||||
if game and Manager.setVerbose._output ~= true then Manager.setVerbose._output=true game.write_file('verbose.log',rtn)
|
||||
elseif game then game.write_file('verbose.log','\n'..rtn,true) end
|
||||
-- standard print and log, _log is a version of log which is ln1 of control.lua for shorter log lines
|
||||
if print then print(rtn) end
|
||||
if _log then _log(rtn) end
|
||||
end
|
||||
|
||||
--- Used to call the output of the verbose when the current state allows it
|
||||
-- @usage Manager.verbose('Hello, World!')
|
||||
-- @tparm rtn string the value that will be returned though verbose output
|
||||
-- @tparm action string is used to decide which verbose this is error || event etc
|
||||
Manager.verbose = function(rtn,action)
|
||||
local settings = Manager.setVerbose
|
||||
local state = Manager.currentState
|
||||
-- if ran in a module the the global module_name is present
|
||||
if module_name then rtn='['..module_name..'] '..rtn
|
||||
else rtn='[FSM] '..rtn end
|
||||
-- module_verbose is a local override for a file, action is used in the manager to describe an extra type, state is the current state
|
||||
-- if action is true then it will always trigger verbose
|
||||
if module_verbose or action and (action == true or settings[action]) or settings[state] then
|
||||
if type(settings.output) == 'function' then
|
||||
-- calls the output function, not pcalled as if this fails some thing is very wrong
|
||||
settings.output(rtn)
|
||||
else
|
||||
error('Verbose set for: '..state..' but output can not be called',2)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Main logic for allowing verbose at different stages though out the script
|
||||
-- @usage Manager.setVerbose{output=log}
|
||||
-- @tparam newTbl table the table that will be searched for settings to be updated
|
||||
-- @usage Manager.setVerbose[setting] -- returns the value of that setting
|
||||
-- @usage tostring(Manager.setVerbose) -- returns a formated list of the current settings
|
||||
Manager.setVerbose = setmetatable(
|
||||
{
|
||||
selfInit=true, -- called while the manager is being set up
|
||||
moduleLoad=false, -- when a module is required by the manager
|
||||
moduleInit=false, -- when and within the initation of a module
|
||||
moduleEnv=false, -- during module runtime, this is a global option set within each module(module_verbose=true ln:1) for fine control
|
||||
eventRegistered=false, -- when a module registers its event handlers
|
||||
errorCaught=true, -- when an error is caught during runtime
|
||||
output=Manager._verbose, -- can be: print || log || or other function
|
||||
_output={} -- a constant value that can used to store output data
|
||||
},
|
||||
{
|
||||
__metatable=false,
|
||||
__call=function(tbl,newTbl)
|
||||
-- does not allow any new keys, but will override any existing ones
|
||||
for key,value in pairs(newTbl) do
|
||||
if rawget(tbl,key) ~= nil then
|
||||
Manager.verbose('Verbose for: "'..key..'" has been set to: '..tostring(value))
|
||||
rawset(tbl,key,value)
|
||||
end
|
||||
end
|
||||
end,
|
||||
__newindex=function(tbl,key,value)
|
||||
-- stops creationg of new keys
|
||||
error('New settings cannot be added during runtime',2)
|
||||
end,
|
||||
__index=function(tbl,key)
|
||||
-- will always return a value, never nil
|
||||
return rawget(tbl,key) or false
|
||||
end,
|
||||
__tostring=function(tbl)
|
||||
-- a simple concat function for the settings
|
||||
local rtn = ''
|
||||
for key,value in pairs(tbl) do
|
||||
if type(value) == 'boolean' then
|
||||
rtn=rtn..key..': '..tostring(value)..', '
|
||||
end
|
||||
end
|
||||
return rtn:sub(1,-3)
|
||||
end
|
||||
}
|
||||
)
|
||||
-- call to verbose to show start up, will always be present
|
||||
Manager.verbose('Current state is now: "selfInit"; The verbose state is: '..tostring(Manager.setVerbose.selfInit),true)
|
||||
|
||||
--- Creates a sand box envorment and runs a callback in that sand box; provents global pollution
|
||||
-- @usage Manager.sandbox(callback) -- return sandbox, success, other returns from callback
|
||||
-- @tparam callback function the function that will be ran in the sandbox
|
||||
-- @param[opt] any other params that the function will use
|
||||
-- @usage Manager.sandbox() -- returns and empty sandbox
|
||||
-- @usage Manager.sandbox[key] -- returns the sand box value in that key
|
||||
Manager.sandbox = setmetatable({
|
||||
-- can not use existing keys of _G
|
||||
verbose=Manager.verbose,
|
||||
module_verbose=false,
|
||||
module_exports=false
|
||||
},{
|
||||
__metatable=false,
|
||||
__call=function(tbl,callback,env,...)
|
||||
if type(callback) == 'function' then
|
||||
-- creates a new sandbox env
|
||||
local sandbox = tbl()
|
||||
-- new indexs are saved into sandbox and if _G does not have the index then look in sandbox
|
||||
setmetatable(env,{__index=sandbox})
|
||||
setmetatable(_G,{__index=env,__newindex=sandbox})
|
||||
-- runs the callback
|
||||
local rtn = {pcall(callback,...)}
|
||||
local success = table.remove(rtn,1)
|
||||
-- this is to allow modules to be access with out the need of using Mangaer[name] also keeps global clean
|
||||
setmetatable(_G,{__index=ReadOnlyManager})
|
||||
if success then return sandbox, success, rtn
|
||||
else return sandbox, success, rtn[1] end
|
||||
else return setmetatable({},{__index=tbl}) end
|
||||
end
|
||||
})
|
||||
|
||||
--- Loads the modules that are present in the index list
|
||||
-- @usage Manager.loadModules() -- loads all moddules in the index list
|
||||
-- @usage #Manager.loadModules -- returns the number of modules loaded
|
||||
-- @usage tostring(Manager.loadModules) -- returns a formatted list of all modules loaded
|
||||
-- @usage pairs(Manager.loadModules) -- loops over the loaded modules moduleName, module
|
||||
Manager.loadModules = setmetatable({},
|
||||
{
|
||||
__metatable=false,
|
||||
__call=function(tbl)
|
||||
-- ReadOnlyManager used to trigger verbose change
|
||||
ReadOnlyManager.currentState = 'moduleLoad'
|
||||
-- goes though the index looking for modules
|
||||
for module_name,location in pairs (moduleIndex) do
|
||||
Manager.verbose('Loading module: "'..module_name..'"; Location: '..location)
|
||||
-- runs the module in a sandbox env
|
||||
local sandbox, success, module = Manager.sandbox(require,{module_name=setupModuleName(module_name),module_location=location},location)
|
||||
-- extracts the module into a global index table for later use
|
||||
if success then
|
||||
-- verbose to notifie of any globals that were attempted to be created
|
||||
local globals = ''
|
||||
for key,value in pairs(sandbox) do globals = globals..key..', ' end
|
||||
if globals ~= '' then Manager.verbose('Globals caught in "'..module_name..'": '..globals:sub(1,-3),'errorCaught') end
|
||||
Manager.verbose('Successfully loaded: "'..module_name..'"; Location: '..location)
|
||||
-- sets that it has been loaded and adds to the loaded index
|
||||
-- if you prefere module_exports can be used rather than returning the module
|
||||
if type(tbl[module_name]) == 'nil' then
|
||||
-- if it is a new module then creat the new index
|
||||
if sandbox.module_exports and type(sandbox.module_exports) == 'table'
|
||||
then tbl[module_name] = sandbox.module_exports
|
||||
else tbl[module_name] = table.remove(module,1) end
|
||||
elseif type(tbl[module_name]) == 'table' then
|
||||
-- if this module adds onto an existing one then append the keys
|
||||
if sandbox.module_exports and type(sandbox.module_exports) == 'table'
|
||||
then for key,value in pairs(sandbox.module_exports) do tbl[module_name][key] = value end
|
||||
else for key,value in pairs(table.remove(module,1)) do tbl[module_name][key] = value end end
|
||||
else
|
||||
-- if it is a function then it is still able to be called even if more keys are going to be added
|
||||
-- if it is a string then it will act like one; if it is a number well thats too many metatable indexs
|
||||
tbl[module_name] = setmetatable({__old=tbl[module_name]},{
|
||||
__call=function(tbl,...) if type(tbl.__old) == 'function' then tbl.__old(...) else return tbl.__old end end,
|
||||
__tostring=function(tbl) return tbl.__old end,
|
||||
__concat=function(tbl,val) return tbl.__old..val end
|
||||
})
|
||||
-- same as above for adding the keys to the table
|
||||
if sandbox.module_exports and type(sandbox.module_exports) == 'table'
|
||||
then for key,value in pairs(sandbox.module_exports) do tbl[module_name][key] = value end
|
||||
else for key,value in pairs(table.remove(module,1)) do tbl[module_name][key] = value end end
|
||||
end
|
||||
-- if there is a module by this name in _G ex table then it will be indexed to the new module
|
||||
if rawget(_G,module_name) then setmetatable(rawget(_G,module_name),{__index=tbl[module_name]}) end
|
||||
else
|
||||
Manager.verbose('Failed load: "'..module_name..'"; Location: '..location..' ('..module..')','errorCaught')
|
||||
end
|
||||
end
|
||||
-- new state for the manager to allow control of verbose
|
||||
ReadOnlyManager.currentState = 'moduleInit'
|
||||
-- runs though all loaded modules looking for on_init function; all other modules have been loaded
|
||||
for module_name,data in pairs(tbl) do
|
||||
-- looks for init so that init or on_init can be used
|
||||
if type(data) == 'table' and data.init and data.on_init == nil then data.on_init = data.init data.init = nil end
|
||||
if type(data) == 'table' and data.on_init and type(data.on_init) == 'function' then
|
||||
Manager.verbose('Initiating module: "'..module_name)
|
||||
local sandbox, success, err = Manager.sandbox(data.on_init,{module_name=setupModuleName(module_name)},data)
|
||||
if success then
|
||||
Manager.verbose('Successfully Initiated: "'..module_name..'"')
|
||||
else
|
||||
Manager.verbose('Failed Initiation: "'..module_name..'" ('..err..')','errorCaught')
|
||||
end
|
||||
-- clears the init function so it cant be used in runtime
|
||||
data.on_init = nil
|
||||
end
|
||||
end
|
||||
-- this could also be called runtime
|
||||
ReadOnlyManager.currentState = 'moduleEnv'
|
||||
end,
|
||||
__len=function(tbl)
|
||||
-- counts the number of loaded modules
|
||||
local rtn = 0
|
||||
for key,value in pairs(tbl) do
|
||||
rtn = rtn + 1
|
||||
end
|
||||
return rtn
|
||||
end,
|
||||
__tostring=function(tbl)
|
||||
-- a concat of all the loaded modules
|
||||
local rtn = 'Load Modules: '
|
||||
for key,value in pairs(tbl) do
|
||||
rtn=rtn..key..', '
|
||||
end
|
||||
return rtn:sub(1,-3)
|
||||
end
|
||||
}
|
||||
)
|
||||
|
||||
--- A more detailed replacement for the lua error function to allow for handlers to be added; repleaces default error so error can be used instead of Manager.error
|
||||
-- @usage Manager.error(err) -- calls all error handlers that are set or if none then prints to game and if that fails crashs game
|
||||
-- @tparam err string the err string that will be passed to the handlers
|
||||
-- @usage Manager.error() -- returns an error constant that can be used to crash game
|
||||
-- @usage Manager.error(Manager.error()) -- crashs the game
|
||||
-- @usage Manager.error.addHandler(name,callback) -- adds a new handler if handler returns Manager.error() then game will crash
|
||||
-- @tparam name string || fucntion the name that is given to the callback || the callback that will be used
|
||||
-- @tparam[opt:type(name)=='function'] callback function if name is given as a string this will be the callback used
|
||||
-- @usage Manager.error[name] -- returns the handler of that name if present
|
||||
-- @usage #Manager.error -- returns the number of error handlers that are present
|
||||
-- @usage pairs(Manager.error) -- loops over only the error handlers handler_name,hander
|
||||
Manager.error = setmetatable({
|
||||
__error_call=error,
|
||||
__error_const={},
|
||||
__error_handler=function(handler_name,callback)
|
||||
-- when handler_name is a string it is expeced that callback is a function; other wise handler_name must be a function
|
||||
if type(handler_name) == 'string' and type(callback) == 'function' then Manager.error[handler_name]=callback
|
||||
elseif type(handler_name) == 'function' then table.insert(Manager.error,handler_name)
|
||||
else Manager.error('Handler is not a function',2) end
|
||||
end
|
||||
},{
|
||||
__metatalbe=false,
|
||||
__call=function(tbl,err,...)
|
||||
-- if no params then return the error constant
|
||||
if err == nil then return rawget(tbl,'__error_const') end
|
||||
-- if the error constant is given crash game
|
||||
if err == rawget(tbl,'__error_const') then Manager.verbose('Force Stop','errorCaught') rawget(tbl,'__error_call')('Force Stop',2) end
|
||||
-- other wise treat the call as if its been passed an err string
|
||||
if #tbl > 0 then
|
||||
-- there is at least one error handler loaded; loops over the error handlers
|
||||
for handler_name,callback in pairs(tbl) do
|
||||
local success, err = pcall(callback,err,...)
|
||||
if not success then Manager.verbose('Error handler: "'..handler_name..'" failed to run ('..err..')','errorCaught') end
|
||||
-- if the error constant is returned from the handler then crash the game
|
||||
if err == rawget(tbl,'__error_const') then Manager.verbose('Force Stop by: '..handler_name,'errorCaught') rawget(tbl,'__error_call')('Force Stop by: '..handler_name) end
|
||||
end
|
||||
elseif game then
|
||||
-- there are no handlers loaded so it will print to the game if loaded
|
||||
Manager.verbose('No error handlers loaded; Default game print used','errorCaught')
|
||||
game.print(err)
|
||||
else
|
||||
-- all else fails it will crash the game with the error code
|
||||
Manager.verbose('No error handlers loaded; Game not loaded; Forced crash: '..err,'errorCaught')
|
||||
rawget(tbl,'__error_call')(err,2)
|
||||
end
|
||||
end,
|
||||
__index=function(tbl,key)
|
||||
-- this allows the __error_handler to be called from many different names
|
||||
if key:lower() == 'addhandler' or key:lower() == 'sethandler' or key:lower() == 'handler' or key:lower() == 'register' then return rawget(tbl,'__error_handler')
|
||||
else rawget(tbl,'__error_call')('Invalid index for error handler; please use build in methods.') end
|
||||
end,
|
||||
__newindex=function(tbl,key,value)
|
||||
-- making a new index adds it as a handler
|
||||
if type(value) == 'function' then
|
||||
Manager.verbose('Added Error Handler: "'..key..'"','eventRegistered')
|
||||
rawset(tbl,key,value)
|
||||
end
|
||||
end,
|
||||
__len=function(tbl)
|
||||
-- counts the number of handlers there are
|
||||
local rtn=0
|
||||
for handler_name,callback in pairs(tbl) do
|
||||
rtn=rtn+1
|
||||
end
|
||||
return rtn
|
||||
end,
|
||||
__pairs=function(tbl)
|
||||
-- will not return any of the three core values as part of pairs
|
||||
local function next_pair(tbl,k)
|
||||
local v
|
||||
k, v = next(tbl, k)
|
||||
if k == '__error_call' or k == '__error_const' or k == '__error_handler' then return next_pair(tbl,k) end
|
||||
if type(v) == 'function' then return k,v end
|
||||
end
|
||||
return next_pair, tbl, nil
|
||||
end
|
||||
})
|
||||
-- overrides the default error function
|
||||
error=Manager.error
|
||||
|
||||
-- event does work a bit differnt from error, and if event breaks error is the fallback
|
||||
--- Event handler that modules can use, each module can register one function per event
|
||||
-- @usage Manager.event[event_name] = callback -- sets the callback for that event
|
||||
-- @usage Manager.event[event_name] = nil -- clears the callback for that event
|
||||
-- @usage Manager.event(event_name,callback) -- sets the callback for that event
|
||||
-- @usage Manager.event[event_name] -- returns the callback for that event or the event id if not registered
|
||||
-- @usage Manager.event(event_name) -- runs all the call backs for that event
|
||||
-- @tparam event_name int|string index that referes to an event
|
||||
-- @tparam callback function the function that will be set for that event
|
||||
-- @usage Manager.event() -- returns the stop value for the event proccessor, if returned during an event will stop all other callbacks
|
||||
-- @usage #Manager.event -- returns the number of callbacks that are registered
|
||||
-- @usage pairs(Manager.events) -- returns event_id,table of callbacks
|
||||
Manager.event = setmetatable({
|
||||
__stop={},
|
||||
__events={},
|
||||
__event=script.on_event,
|
||||
__generate=script.generate_event_name,
|
||||
__get_handler=script.get_event_handler,
|
||||
__raise=script.raise_event,
|
||||
__init=script.on_init,
|
||||
__load=script.on_load,
|
||||
__config=script.on_configuration_changed,
|
||||
events=defines.events
|
||||
},{
|
||||
__metatable=false,
|
||||
__call=function(tbl,event_name,new_callback,...)
|
||||
-- if no params then return the stop constant
|
||||
if event_name == nil then return rawget(tbl,'__stop') end
|
||||
-- if the event name is a table then loop over each value in that table
|
||||
if type(event_name) == 'table' then
|
||||
for key,_event_name in pairs(event_name) do tbl(_event_name,new_callback,...) end return
|
||||
end
|
||||
-- convert the event name to a number index
|
||||
event_name = tonumber(event_name) or tbl.names[event_name]
|
||||
-- if there is a callback present then set new callback rather than raise the event
|
||||
if type(new_callback) == 'function' then
|
||||
Manager.event[event_name] = new_callback return
|
||||
end
|
||||
-- other wise raise the event and call every callback; no use of script.raise_event due to override
|
||||
if type(tbl[event_name]) == 'table' then
|
||||
for module_name,callback in pairs(tbl[event_name]) do
|
||||
-- loops over the call backs and which module it is from
|
||||
if type(callback) ~= 'function' then error('Invalid Event Callback: "'..event_name..'/'..module_name..'"') end
|
||||
local sandbox, success, err = Manager.sandbox(callback,{module_name=setupModuleName(module_name)},new_callback,...)
|
||||
if not success then Manager.verbose('Event Failed: "'..tbl.names[event_name]..'/'..module_name..'" ('..err..')','errorCaught') error('Event Failed: "'..event_name..'/'..module_name..'" ('..err..')') end
|
||||
-- if stop constant is returned then stop further processing
|
||||
if err == rawget(tbl,'__stop') then Manager.verbose('Event Haulted By: "'..module_name..'"','errorCaught') break end
|
||||
end
|
||||
end
|
||||
end,
|
||||
__newindex=function(tbl,key,value)
|
||||
-- handles the creation of new event handlers
|
||||
if type(value) ~= 'function' and type(value) ~= nil then error('Attempted to set a non function value to an event',2) end
|
||||
-- checks for a global module name that is present
|
||||
local module_name = module_name or 'FSM'
|
||||
-- converts the key to a number index for the event
|
||||
key = tonumber(key) or tbl.names[key]
|
||||
Manager.verbose('Added Handler: "'..tbl.names[key]..'"','errorCaught')
|
||||
-- checks that the event has a valid table to store callbacks; if its not valid it will creat it and register a real event handler
|
||||
if not rawget(rawget(tbl,'__events'),key) then rawget(tbl,'__event')(key,function(...) tbl(...) end) rawset(rawget(tbl,'__events'),key,{}) end
|
||||
-- adds callback to Manager.event.__events[event_id][module_name]
|
||||
rawset(rawget(rawget(tbl,'__events'),key),module_name,value)
|
||||
end,
|
||||
__index=function(tbl,key)
|
||||
-- proforms different look ups depentding weather the current module has an event handler registered
|
||||
if module_name then
|
||||
-- first looks for the event callback table and then under the module name; does same but converts the key to a number; no handler regisered so returns the converted event id
|
||||
return rawget(rawget(tbl,'__events'),key) and rawget(rawget(rawget(tbl,'__events'),key),module_name)
|
||||
or rawget(rawget(tbl,'__events'),rawget(tbl,'names')[key]) and rawget(rawget(rawget(tbl,'__events'),rawget(tbl,'names')[key]),module_name)
|
||||
or rawget(tbl,'names')[key]
|
||||
else
|
||||
-- if there is no module present then it will return the full list of regisered handlers; or other wise the converted event id
|
||||
return rawget(rawget(tbl,'__events'),key) or rawget(rawget(tbl,'__events'),rawget(tbl,'names')[key]) or rawget(tbl,'names')[key]
|
||||
end
|
||||
end,
|
||||
__len=function(tbl)
|
||||
-- counts every handler that is regised not just the the number of events with handlers
|
||||
local rtn=0
|
||||
for event,callbacks in pairs(tbl) do
|
||||
for module,callback in pairs(callbacks) do
|
||||
rtn=rtn+1
|
||||
end
|
||||
end
|
||||
return rtn
|
||||
end,
|
||||
__pairs=function(tbl)
|
||||
-- will loops over the event handlers and not Manager.event
|
||||
local function next_pair(tbl,k)
|
||||
k, v = next(rawget(tbl,'__events'), k)
|
||||
if type(v) == 'table' then return k,v end
|
||||
end
|
||||
return next_pair, tbl, nil
|
||||
end
|
||||
})
|
||||
--- Sub set to Manger.event and acts as a coverter between event_name and event_id
|
||||
-- @usage Manager.event[event_name] -- see above, can not be accessed via Manager.event.names
|
||||
rawset(Manager.event,'names',setmetatable({},{
|
||||
__index=function(tbl,key)
|
||||
if type(key) == 'number' or tonumber(key) then
|
||||
-- if it is a number then it will first look in the chache
|
||||
if rawget(tbl,key) then return rawget(tbl,key) end
|
||||
-- if it is a core event then it will simply return
|
||||
if key == 'on_init' or key == 'init' then
|
||||
rawset(tbl,key,-1)
|
||||
elseif key == 'on_load' or key == 'load' then
|
||||
rawset(tbl,key,-2)
|
||||
elseif key == 'on_configuration_changed' or key == 'configuration_changed' then
|
||||
rawset(tbl,key,-3)
|
||||
else
|
||||
-- if it is not a core event then it does a value look up on Manager.events aka defines.events
|
||||
for event,id in pairs(rawget(Manager.event,'events')) do
|
||||
if id == key then rawset(tbl,key,event) end
|
||||
end
|
||||
end
|
||||
-- returns the value from the chache after being loaded in
|
||||
return rawget(tbl,key)
|
||||
-- if it is a string then no reverse look up is required
|
||||
else return rawget(rawget(Manager.event,'events'),key) end
|
||||
end
|
||||
}))
|
||||
--over rides for the base values; can be called though Event
|
||||
Event=setmetatable({},{__index=function(tbl,key) return Manager.event[key] or script[key] or error('Invalid Index To Table Event') end})
|
||||
script.mod_name = setmetatable({},{
|
||||
__index=function(tbl,key) return _G.module_name end,
|
||||
__newindex=function(tbl,key,value) error('Module Name Is Read Only') end,
|
||||
__tostring=function(tbl) return _G.module_name end,
|
||||
__concat=function(tbl,val) return _G.module_name..val end,
|
||||
__metatable=false,
|
||||
})
|
||||
script.on_event=Manager.event
|
||||
script.raise_event=Manager.event
|
||||
script.on_init=function(callback) Manager.event(-1,callback) end
|
||||
script.on_load=function(callback) Manager.event(-2,callback) end
|
||||
script.on_configuration_changed=function(callback) Manager.event(-3,callback) end
|
||||
script.get_event_handler=function(event_name) return type(Manager.event[event_name]) == 'function' and Manager.event[event_name] or nil end
|
||||
script.generate_event_name=function(event_name) local event_id = Manager.event.__generate() local event_name = event_name or event_id Manager.event.events[event_name]=event_id return event_id end
|
||||
-- to do set up nth tick
|
||||
|
||||
return ReadOnlyManager
|
||||
88
control.lua
88
control.lua
@@ -1,3 +1,4 @@
|
||||
function _log(...) log(...) end
|
||||
--[[
|
||||
Explosive Gaming
|
||||
|
||||
@@ -8,78 +9,15 @@ Discord: https://discord.gg/r6dC2uK
|
||||
]]
|
||||
--Please Only Edit Below This Line-----------------------------------------------------------
|
||||
|
||||
-- Replaces the base error function
|
||||
_error = error
|
||||
error = function(err)
|
||||
verbose('Error Called: '..err)
|
||||
if _G.error_handle and type(error_handle) == 'function' then
|
||||
verbose('Exception Caught By Error Handle')
|
||||
local success, _err = pcall(error_handle,err)
|
||||
if not success then _error({handle=_err,err=err}) end
|
||||
elseif _G.Game and game then
|
||||
verbose('Exception Caught By Game Print')
|
||||
if Game.print_all(err) == 0 then
|
||||
_error(err)
|
||||
end
|
||||
else
|
||||
verbose('Failed to catch error')
|
||||
_error(err)
|
||||
end
|
||||
end
|
||||
-- Replaces the base require function and verbose function
|
||||
_verbose = false -- Set to true for more on the loading of the files
|
||||
function verbose(str) if _verbose then log(str) print(str) end end
|
||||
verbose('============================= START =============================')
|
||||
require_return_err = false -- Set to false when removing files; set to true for debuging
|
||||
_require = require
|
||||
require = function(path)
|
||||
local _path = path
|
||||
if string.sub(path,1) ~= '/' then path = '/'..path end
|
||||
local _return = {pcall(_require,path)}
|
||||
if not table.remove(_return, 1) then
|
||||
local __return = {pcall(_require,'/Addons'..path)}
|
||||
if not table.remove(__return, 1) then
|
||||
verbose('Failed to load: '.._path..' ('.._return[1]..')')
|
||||
verbose('Also Attemped: /Addons'..path..' ('..__return[1]..')')
|
||||
if require_return_err then error(unpack(_return)) end
|
||||
else verbose('Loaded: '.._path) return unpack(__return) end
|
||||
else verbose('Loaded: '.._path) end
|
||||
return unpack(_return)
|
||||
end
|
||||
|
||||
verbose('Begain Base Lib Loading')
|
||||
require('mod-gui')
|
||||
-- Loads the stdlib and allows Core Game and Event
|
||||
Color, Game, Event = require('StdLib/load'){'Color','Game','Event'}
|
||||
|
||||
-- loads the ExpLib, functions are placed into the lua global
|
||||
local ExpLib = require 'ExpLib'
|
||||
verbose('ExpLib Extraction')
|
||||
ExpLib._unpack_to_G(ExpLib)
|
||||
|
||||
verbose('Begain Core File Loading')
|
||||
-- Loads the ExpCore files. These are need in order to run the other addons
|
||||
Ranking, Sync, Server, Gui = require('ExpCore/load'){'Ranking','Sync','Server','Gui'}
|
||||
verbose('Gui Test Initiation')
|
||||
local success,err = require('ExpCore/GuiParts/test')
|
||||
if success then Gui.test = err else verbose('No Test Present') end
|
||||
if Gui.popup then verbose('Gui Popup Initiation') Gui.popup._load() end
|
||||
if Sync._load then verbose('Sync Initiation') Sync._load() end
|
||||
-- Loads the ranks that Ranking uses
|
||||
verbose('Base Ranks Initiation')
|
||||
require('ExpCore/ranks')
|
||||
-- Loads any edits that are not need in core pcall as file may not be present
|
||||
verbose('Extented Ranks Initiation')
|
||||
require('Addons/playerRanks')
|
||||
-- Makes sure that all the little details are cleaned up
|
||||
verbose('Ranking Initiation')
|
||||
Ranking._auto_edit_ranks()
|
||||
-- Loads all the addons
|
||||
verbose('Begain Addons Loading')
|
||||
local success,err = pcall(require,'Addons/load')
|
||||
if not success then error(err) end
|
||||
-- Loads anything that does not use ExpCore (source given in the file)
|
||||
verbose('Begain Stand Alone Loading')
|
||||
local success,err = pcall(require,'StandAlone/load')
|
||||
if not success then error(err) end
|
||||
verbose('============================== END ==============================')
|
||||
-- File Which Factorio Will Call
|
||||
Manager = require("FactorioSoftmodManager")
|
||||
Manager.setVerbose{
|
||||
selfInit=true, -- called while the manager is being set up
|
||||
moduleLoad=true, -- when a module is required by the manager
|
||||
moduleInit=true, -- when and within the initation of a module
|
||||
moduleEnv=true, -- during module runtime, this is a global option set within each module for fine control
|
||||
eventRegistered=true, -- when a module registers its event handlers
|
||||
errorCaught=true, -- when an error is caught during runtime
|
||||
output=Manager._verbose -- can be: can be: print || log || other function
|
||||
}
|
||||
Manager() -- can be Manager.loadModules() if called else where
|
||||
144
modules/ExpGamingLib/control.lua
Normal file
144
modules/ExpGamingLib/control.lua
Normal file
@@ -0,0 +1,144 @@
|
||||
--[[
|
||||
Explosive Gaming
|
||||
|
||||
This file can be used with permission but this and the credit below must remain in the file.
|
||||
Contact a member of management on our discord to seek permission to use our code.
|
||||
Any changes that you may make to the code are yours but that does not make the script yours.
|
||||
Discord: https://discord.gg/r6dC2uK
|
||||
]]
|
||||
--Please Only Edit Below This Line-----------------------------------------------------------
|
||||
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 sandboxed; 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
|
||||
function ExpLib.get_env()
|
||||
local level = 2
|
||||
local env = setmetatable({},{__index=_G})
|
||||
while true do
|
||||
if not debug.getinfo(level-1) then break end
|
||||
local i = 1
|
||||
while true do
|
||||
local name, value = debug.getlocal(level,i)
|
||||
if not name then break else env[name] = value end
|
||||
i=i+1
|
||||
end
|
||||
level=level+1
|
||||
if debug.getinfo(level-1).namewhat == 'global' then break end
|
||||
end
|
||||
return env
|
||||
end
|
||||
|
||||
--- Compear types faster for faster valadation 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 bolean -- 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
|
||||
|
||||
--- 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, ingroned 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)
|
||||
local colour = ExpLib.is_type(colour) == 'table' and colour or defines.color[colour]
|
||||
local player = player or game.player
|
||||
local function _return(callback,rtn)
|
||||
if ExpLib.is_type(rtn,'table') then
|
||||
-- test for: userdata, locale string, table with __tostring meta method, any other table
|
||||
if ExpLib.is_type(rtn.__self,'userdata') then callback('Cant Display Userdata',colour)
|
||||
elseif ExpLib.is_type(rtn[1],'string') and string.find(rtn[1],'.+[.].+') and not string.find(rtn[1],'%s') then callback(rtn,colour)
|
||||
elseif getmetatable(rtn) ~= nil and not tostring(rtn):find('table: 0x') then callback(tostring(rtn),colour)
|
||||
else callback(table.tostring(rtn),colour) end
|
||||
-- test for: function
|
||||
elseif ExpLib.is_type(rtn,'function') then callback('Cant Display Functions',colour)
|
||||
-- else just call tostring
|
||||
else callback(tostring(rtn),colour) end
|
||||
end
|
||||
if player then
|
||||
-- allows any vaild player identifier to be used
|
||||
local 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'}
|
||||
_return(player.print,rtn)
|
||||
else _return(rcon.print,rtn) 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
|
||||
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
|
||||
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
|
||||
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 debuging
|
||||
-- @usage Gui_tree(root) -- returns all children of gui recusivly
|
||||
-- @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
|
||||
|
||||
-- unpacks lib to _G on module init
|
||||
function ExpLib.on_init(self)
|
||||
self:unpack_to_G()
|
||||
end
|
||||
|
||||
return ExpLib
|
||||
14
modules/ExpGamingLib/softmod.json
Normal file
14
modules/ExpGamingLib/softmod.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"name": "ExpGamingLib",
|
||||
"module": "ExpLib",
|
||||
"description": "Adds some common functions used though out all ExpGaming modules",
|
||||
"keywords": ["ExpGaming","Lib"],
|
||||
"version": "1.0.0",
|
||||
"location": "nil",
|
||||
"main": "control",
|
||||
"dependencies": {},
|
||||
"author": "Cooldude2606",
|
||||
"contact": "Discord: Cooldude2606#5241",
|
||||
"license": "https://github.com/badgamernl/explosivegaming-main/blob/master/LICENSE"
|
||||
}
|
||||
|
||||
3
modules/index.lua
Normal file
3
modules/index.lua
Normal file
@@ -0,0 +1,3 @@
|
||||
return {
|
||||
['ExpLib']='/modules/ExpGamingLib/control',
|
||||
}
|
||||
Reference in New Issue
Block a user