Added moduole: ExpGamingCore.Server

This commit is contained in:
Cooldude2606
2018-06-01 16:12:39 +01:00
parent 22d3efc4a1
commit 5eb8600411
9 changed files with 302 additions and 204 deletions

View File

@@ -1,60 +1,67 @@
--[[
Explosive Gaming
--- Adds a thread system and event listening and a admin bypass (recommend to disable /c and use optional /interface)
-- @module ExpGamingCore.Server
-- @alias Server
-- @author Cooldude2606
-- @license https://github.com/explosivegaming/scenario/blob/master/LICENSE
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-----------------------------------------------------------
-- server allows control over threads and other features the devs missed out
local Server = {}
Server._thread = {}
--- Returns a un-used uuid (better system needed)
-- @usage obj.uuid = Server.new_uuid()
--- Global Table
-- @table global
local global = global{
all={_n=0}, -- a list of every thread (indexed by uuid)
queue={}, -- an index for threads which will be resolved (contains uuids)
tick={}, -- an index for threads which will run every tick (contains uuids)
timeout={}, -- an index for threads which will timeout (contains uuids)
events={}, -- an index of threads based on event ids (contains uuids)
paused={}, -- an index of pasued threads (contains uuids)
named={}, -- a name index for thread uuids
print_to={}, -- contains players that event details will be printed to
uuid=nil -- contains the random number generator for the uuid system
}
--- Used to generate a new uuid for the thread system
-- @usage local uuid = tostring(Server.uuid) -- calling tostring locks the value
-- @treturn string the new uuid
function Server.new_uuid()
local uuid = tostring(Server._uuid()())
uuid = string.to_hex('uuid'..uuid)
return uuid
end
Server.uuid = add_metatable({},function()
if not global.uuid then global.uuid = game.create_random_generator() end
return global.uuid()
end,function()
return string.to_hex(tostring(Server.uuid()))
end)
-- use this to change the location of the server uuids
function Server._uuid(reset)
global.exp_core = not reset and global.exp_core or {}
global.exp_core.uuids = not reset and global.exp_core.uuids or game.create_random_generator()
return global.exp_core.uuids
end
--- Redirect to the thread index
-- @usage Server.threads -- return #global.all
-- @usage Server.threads -- return global.all
-- @treturn[1] number the number of threads
-- @treturn[2] table table of all threads
Server.threads = setmetatable({},{
__call=function(tbl) return global.all._n end,
__index=function(tbl,key) return rawget(global.all,key) end,
__newindex=function(tbl,key,value) rawset(global.all,key,value) end,
__pairs=function(tbl)
local tbl = global.all
local function next_pair(tbl,k)
k, v = next(tbl, k)
if type(v) ~= nil and k ~= '_n' then return k,v end
end
return next_pair, tbl, nil
end
})
--- Returns either the number of threads or a able of threads
-- @usage Server.threads() -- return {...}
-- Server.threads(true) -- return int
-- @tparam[opt=nil] bolean count true to return the number of threads
-- @return either a list of threads or a number
function Server.threads(count)
return count and Server._threads().all._n or Server._threads().all
end
--- Generates a new thread object
-- @usage Server.new_thread{name='foo',data={}}
-- @tparam table obj the atributes to give to the thread
-- @treturn Server._thread the new thread created
function Server.new_thread(obj) return Server._thread:create(obj) end
-- use this to change the location of the server threads
-- all stores the threads indexed uuid, the other three only store the uuid's to index in the all table
function Server._threads(reset)
global.exp_core = not reset and global.exp_core or {}
global.exp_core.threads = not reset and global.exp_core.threads or {print_to={},queue={},tick={},timeout={},events={},all={_n=0},paused={},named={}}
return global.exp_core.threads
end
-- see thread:create (this was done so thread can remain local)
function Server.new_thread(obj)
return Server._thread:create(obj)
end
--- Used to get a thread via it's uuid or by name if one is given
--- Used to get a thread via uuid or name (if one is assied)
-- @usage Server.get_thread('decon') -- return thread
-- @param mixed either a uuid or the name given to a thread
-- @treturn table the thread by that name or uuid
-- @treturn[1] Server._thread the thread by that name or uuid
-- @treturn[2] boolean if false is returned then no thread existes
function Server.get_thread(mixed)
local threads = Server._threads()
local threads = global
if threads.named[mixed] then return threads.all[threads.named[mixed]]
elseif threads.paused[mixed] then return threads.all[threads.paused[mixed]]
elseif threads.all[mixed] then return threads.all[mixed]
@@ -63,33 +70,29 @@ end
--- Adds a thread into the resolve queue, can be used to lower lag
-- @usage Server.queue_thread(thread) -- return true/false
-- @tparam table thread_to_queue the thread to add to the queue must have a resolve function (must be open)
-- @treturn boolean was the thread added
-- @tparam Server._thread thread_to_queue the thread to be added to the queue, must be open and have a on_resolve function
-- @treturn boolean was it added successfuly
function Server.queue_thread(thread_to_queue)
if not thread_to_queue and not thread_to_queue.valid and not thread_to_queue:valid() then return false end
if not thread_to_queue._resolve then return false end
table.insert(Server._threads().queue,thread_to_queue.uuid)
table.insert(global.queue,thread_to_queue.uuid)
return true
end
--- Closes all active threads, can use force if it causes errors
-- @usage Server.close_all_threads()
-- Server.close_all_threads(true) -- use if no force makes errors
-- @usage Server.close_all_threads() -- asks all threads to close
-- @usage Server.close_all_threads(true) -- forcefuly close all threads
-- @tparam bolean with_force use force when closing
function Server.close_all_threads(with_force)
if not with_force then
for uuid,next_thread in pairs(Server.threads()) do
if uuid ~= '_n' then next_thread:close() end
end
else
Server._threads(true)
end
for uuid,thread in pairs(Server.threads) do thread:close() end
else global(true) end
end
--- Runs all the theads which have opened with an on_tick event
-- @usage Server.run_tick_threads()
function Server.run_tick_threads()
table.each(Server._threads().tick,function(uuid)
table.each(global.tick,function(uuid)
local next_thread = Server.get_thread(uuid)
if next_thread and next_thread:valid() and next_thread._tick then
local success, err = pcall(next_thread._tick,next_thread)
@@ -101,7 +104,7 @@ end
--- Checks the timeout on all active timeout threads
-- @usage Server.check_timeouts()
function Server.check_timeouts()
table.each(Server._threads().timeout,function(uuid)
table.each(global.timeout,function(uuid)
local next_thread = Server.get_thread(uuid)
if next_thread and next_thread:valid() then
next_thread:check_timeout()
@@ -109,35 +112,51 @@ function Server.check_timeouts()
end)
end
-- for use in debuging
function Server._thread_handler_debuger(player,event,state)
--- Used to print event info to a player
-- @usage Server._thread_debuger('Cooldude2606','on_player_died',true) -- will output event info to 'Cooldude2606' for 'on_player_died'
-- @tparam ?name|index|LuaPlayer player the player that the info will be returned to
-- @tparam ?name|index event the event that info will be returned fo
-- @tparam[opt=toggle] boolean state will info be returned, nil to toggle current state
function Server._thread_debuger(player,event,state)
local player = Game.get_player(player)
local print_to = Server._threads().print_to
local event = tonumber(event) or Manager.event.names[event]
local print_to = global.print_to
print_to[player.index] = print_to[player.index] or {}
print_to[player.index][event] = state
if state then print_to[player.index][event] = state
elseif print_to[player.index][event] then print_to[player.index][event] = false
else print_to[player.index][event] = true end
end
--- Calles all threads on a certain game event (used with script.on_event)
-- @local Server._thread_handler
-- @usage script.on_event(defines.events,Server._thread_handler) -- adds this handler
-- @tparam table event the event that is called
function Server._thread_handler(event)
table.each(Server._threads().print_to,function(print_to,player_index,event)
-- returns to players who have set _thread_debuger to trye
table.each(global.print_to,function(print_to,player_index,event)
if event.name == defines.events.on_tick then return true end
if print_to[event.name] then
player_return(event,defines.textcolor.bg,player_index)
end
end,event)
-- gets the thread uuids
local event_id = event.name
local threads = Server._threads().events[event_id]
local threads = global.events[event_id]
if not threads then return end
-- loops over the uuids
table.each(threads,function(uuid)
local next_thread = Server.get_thread(uuid)
if next_thread and next_thread:valid() then
if is_type(next_thread._events[event_id],'function') then
local success, err = pcall(next_thread._events[event_id],next_thread,event)
if not success then next_thread:error(err) end
local thread = Server.get_thread(uuid)
if thread and thread:valid() then
if is_type(thread._events[event_id],'function') then
-- runs the function in the same env it was created (avoids desyncs)
local sandbox, success, err = Manager.sandbox(thread._events[event_id],thread._env,thread,event)
-- if there is an error it asks the thread to deal with it
if not success then thread:error(err) end
end
end
end)
end
script.on_event(defines.events,Server._thread_handler)
--[[ cant be used V
--- Adds a event handler to tell threads about events
@@ -146,78 +165,96 @@ end
-- @treturn bolean if the handler was added
function Server.add_thread_handler(event)
if not is_type(event,'number') then return false end
local threads = Server._threads()
local threads = global
if not threads.events[event] then
threads.events[event] = {}
Event.register(event,Server._thread_handler)
script.on_event(event,Server._thread_handler)
return true
end
return false
end
]]
--- Given a string or function it will run that function and return any values
--- Acts as a bypass for running functions, can accept a string
-- @usage Server.interface('local x = 1+1 print(x) return x') -- return 2
-- Server.interface('local x = 1+1 print(x)',thread) -- no return
-- @param callback either a function or string which will be ran via pcall
-- @param[opt] use_thread give a thread for the interface to run on (does not need to be open, but cant use on_resolve)
-- @usage Server.interface('local x = 1+1 print(x)',true) -- will creat a thread to run as root (this is the bypass)
-- @tparam ?string|function callback function to be ran
-- @tparam[opt] ?Server._thread|true use_thread run the command on a premade thread or let it make its own
-- @tparam[opt] table env run the env to run the command in must have _env key as true to be
-- @param[opt] ... any args you want to pass to the function
function Server.interface(callback,use_thread,...)
-- @return if no thread then it will return the value(s) returned by the callback
function Server.interface(callback,use_thread,env,...)
if use_thread then
if use_thread == true then use_thread = Server.new_thread{data={callback,...}} end
-- if use_thread is true then it makes a new thread
if use_thread == true then use_thread = Server.new_thread{data={callback,env,...}} end
-- creates the resolve function for the thread
use_thread:on_event('resolve',function(thread)
if is_type(thread.data[1],'function') then
local success, err = pcall(unpack(thread.data))
local callback = table.remove(thread.data,1)
callback = is_type(callback,'function') and callback or loadstring(callback)
local env = table.remove(thread.data,1)
if is_type(env,'table') and env._env == true then
local sandbox, success, err = Manager.sandbox(callback,env,unpack(thread.data))
if not success then error(err) end
return err
else
local callback = table.remove(thread.data,1)
local success, err = pcall(loadstring(callback),unpack(thread.data))
local sandbox, success, err = Manager.sandbox(callback,{},env,unpack(thread.data))
if not success then error(err) end
return err
end
end)
-- opens the thread and then queues it
use_thread:open()
Server.queue_thread(use_thread)
else
if is_type(callback,'function') then
local success, err = pcall(callback,...)
return success, err
local callback = is_type(callback,'function') and callback or loadstring(callback)
if is_type(env,'table') and env._env == true then
local sandbox, success, err = Manager.sandbox(callback,env,unpack(thread.data))
if not success then error(err) end
return err
else
local success, err = pcall(loadstring(callback),...)
return success, err
local sandbox, success, err = Manager.sandbox(callback,{},env,unpack(thread.data))
if not success then error(err) end
return err
end
return false
end
end
-- thread allows you to run fuinction async to the main game
--- The class for the server threads, allows abbilty to run async function
-- @class Thread
-- @alias Server._thread
Server._thread = {}
--- Returns a new thread object
-- @usage new_thread = thread:create()
-- @tparam[opt={}] table obj all are opt {timeout=int,name=str,data=any} advanced users can prefix with _function to avoid the on_function functions
-- @treturn table the new thread object
-- @tparam[opt={}] table obj all values are opt {timeout=int,name=str,data=any}
-- @treturn Server._thread the new thread object
function Server._thread:create(obj)
local obj = obj or {}
setmetatable(obj,{__index=Server._thread})
obj.uuid = Server.new_uuid()
obj.uuid = tostring(Server.uuid)
obj._env = get_env()
obj._env.obj = nil -- provents infinte recusion
return obj
end
-- see Server.queue_thread - this just opens it first
--- Opens and queses a thread
-- @usage Server._thread:queue() -- returns true/false
-- @treturn boolean was the thread queued successfuly
-- @see Server.queue_thread
function Server._thread:queue()
self:open()
return Server.queue_thread(self)
end
--- Test if the thread has all requied parts
-- @usage if thread:valid() then end
-- @tparam bolean skip_location_check true to skip the location check
-- @treturn bolean is the thread valid
-- @usage if thread:valid() then end -- basic test for valid
-- @tparam[opt=false] bolean skip_location_check true to skip the location checking
-- @treturn boolean is the thread valid
function Server._thread:valid(skip_location_check)
local skip_location_check = skip_location_check or false
if is_type(self.uuid,'string') and
skip_location_check or is_type(self.opened,'number') and
skip_location_check or is_type(Server._threads().all[self.uuid],'table') and
skip_location_check or is_type(global.all[self.uuid],'table') and
is_type(self.timeout) or is_type(self.timeout,'number') and
is_type(self.name) or is_type(self.name,'string') and
is_type(self._close) or is_type(self._close,'function') and
@@ -226,64 +263,78 @@ function Server._thread:valid(skip_location_check)
is_type(self._resolve) or is_type(self._resolve,'function') and
is_type(self._success) or is_type(self._success,'function') and
is_type(self._error) or is_type(self._error,'function') then
-- all above must be true to be vaild, must accept nil and function
return true
end
return false
end
--- Opens the thread by storing it in a place the server object can find it
--- Opens the thread; indexs this thread in the global index
-- @usage thread:open() -- return true
-- @treturn bolean if the thread was opened
-- @treturn bolean if the thread was opened successfuly
function Server._thread:open()
-- if the thread is valid and not already opended
if not self:valid(true) or self.opened then return false end
local threads = Server._threads()
local uuid = self.uuid
-- sets the thread to open, this is the tick it was opened
self.opened = game.tick
threads.all[uuid] = threads.all[uuid] or self
threads.all._n = threads.all._n+1
if threads.paused[self.name] then threads.paused[self.name] = nil end
if is_type(self.timeout,'number') then table.insert(threads.timeout,uuid) end
if is_type(self._tick,'function') then table.insert(threads.tick,uuid) end
if is_type(self.name,'string') then threads.named[self.name] = threads.named[self.name] or self.uuid end
-- creats the global index
global.all[uuid] = global.all[uuid] or self
global.all._n = global.all._n+1
-- indexs the thread in other places if it has more function
-- if it was paused before (ie did not run any events) then the index is removed from the paused index
if global.paused[self.name] then global.paused[self.name] = nil end
-- if it has a timeout or on_tick handler then it is indexed in those indexs
if is_type(self.timeout,'number') then table.insert(global.timeout,uuid) end
if is_type(self._tick,'function') then table.insert(global.tick,uuid) end
-- if the thread is given a name then a index from the name to uuid is made
if is_type(self.name,'string') then global.named[self.name] = global.named[self.name] or self.uuid end
-- if there are event handlers then it will loop over them and add them to the event index
if is_type(self._events,'table') then
table.each(self._events,function(callback,event,threads,uuid)
table.each(self._events,function(callback,event,global,uuid)
-- cant be used V
--Server.add_thread_handler(event)
if not threads.events[event] then threads.events[event] = {} end
table.insert(threads.events[event],uuid)
end,threads,self.uuid)
if not global.events[event] then global.events[event] = {} end
table.insert(global.events[event],uuid)
end,global,self.uuid)
end
return true
end
--- Inverse of thread:open() - it removes the thread and calles on_close
--- Inverse of thread:open() - Removes all indexs to this thread, most cases this will cause it to become inassible
-- @usage thread:close() -- return true
-- @treturn bolean if the thread had a on_close function
-- @treturn boolean if the thread had a on_close function
function Server._thread:close()
local threads = Server._threads()
local uuid = self.uuid
local _return = false
-- if there is a call to the threads on close event, will later return true
if is_type(self._close,'function') then pcall(self._close,self) _return = true end
local value,key = table.find(threads.queue,function(v,k,uuid) return v == uuid end,uuid)
if key then table.remove(threads.queue,key) end
local value,key = table.find(threads.timeout,function(v,k,uuid) return v == uuid end,uuid)
if key then table.remove(threads.timeout,key) end
local value,key = table.find(threads.tick,function(v,k,uuid) return v == uuid end,uuid)
if key then table.remove(threads.tick,key) end
-- will search every possible location for this thread and remove it
local value,key = table.find(global.queue,function(v,k,uuid) return v == uuid end,uuid)
if key then table.remove(global.queue,key) end -- queue
local value,key = table.find(global.timeout,function(v,k,uuid) return v == uuid end,uuid)
if key then table.remove(global.timeout,key) end -- timeouts
local value,key = table.find(global.tick,function(v,k,uuid) return v == uuid end,uuid)
if key then table.remove(global.tick,key) end -- on_tick
-- then will look for it in the event handlers and remove it if found
if is_type(self._events,'table') then
table.each(self._events,function(callback,event)
if threads.events[event] then
local value,key = table.find(threads.events[event],function(v,k,uuid) return v == uuid end,uuid)
if key then table.remove(threads.events[event],key) end
if global.events[event] then
local value,key = table.find(global.events[event],function(v,k,uuid) return v == uuid end,uuid)
if key then table.remove(global.events[event],key) end
-- cant be used V
--if #threads.events[event] == 0 then Event.remove(event,Server.game_event) threads.events[event] = nil end
--if #global.events[event] == 0 then Event.remove(event,Server.game_event) global.events[event] = nil end
end
end)
end
-- sets the thread to closed
self.opened=nil
-- unless the thread has a name or is assied to be reopened
if self.reopen == true then self:open() else
if is_type(self.name,'string') then threads.paused[self.name]=self.uuid
else threads.all[uuid] = nil threads.all._n = threads.all._n-1 end
-- if it has a name but not assied to reopen then it will become 'pasued'
if is_type(self.name,'string') then global.paused[self.name]=self.uuid
-- else it will just be wiped from the global index
else global.all[uuid] = nil global.all._n = global.all._n-1 end
end
return _return
end
@@ -294,107 +345,105 @@ end
-- @treturn bolean true if the thread called on_success or on_error
function Server._thread:resolve(...)
local _return = false
-- checks if the resolve haddler is still present
if is_type(self._resolve,'function') then
local success, err = pcall(self._resolve,self,...)
local sandbox, success, err = Manager.sandbox(self._resolve,thread._env,self,...)
if success then
-- if it was successful then it will attemp to call the success handler
if is_type(self._success,'function') then
Server.interface(function(thread,err)
local success,err = pcall(thread._success,thread,err)
-- interface is used as a way to delay the success call till the next tick
Server.interface(function(thread,err)
local sandbox, success, err = Manager.sandbox(thread._success,thread._env,thread,err)
if not success then thread:error(err) end
end,true,self,err)
-- later returns true if there was a call to the success handler
_return = true
end
else
_return = self:error(err)
end
-- if there is an error the thread is asked to deal with it, returns true/false based on result of handler
else _return = self:error(err) end
end
-- closes the thread as it is no longer needed as its command has be ran
self:close()
return _return
end
--- Checks the timeout on a thread - if timedout then it calles on_timeout and closes
--- Checks the timeout on a thread - if timed out then it calles on_timeout and closes
-- @usage thread:check_timeout() -- return true
-- @treturn bolean if the thread timedout
-- @treturn bolean if the thread timed out
function Server._thread:check_timeout()
local _return = false
-- makes sure the thread is still valid
if not self:valid() then return false end
-- checks if the thread has been opened longer than its time out period
if is_type(self.timeout,'number') and game.tick >= (self.opened+self.timeout) then
if is_type(self._timeout,'function') then
pcall(self._timeout,self)
-- we do not care if the time out has caused an error as it is in most cases an error in its own right
Manager.sandbox(self._timeout,thread._env,self)
end
_return = true
-- closes the thread to provent any further event calls
self:close()
end
return _return
end
--- Rasies an error on this thread
--- Used to check and raise the error handler of the thread, if not present it raises an error
-- @usage thread:error(err) -- return true
-- @param err the err to be rasied
-- @treturn bolean did the thread handdle the error
-- @tparam string err the err to be rasied
-- @treturn boolean did the thread have an error handler
function Server._thread:error(err)
local _return = false
if is_type(self._error,'function') then
pcall(self._error,self,err)
_return = true
else
error(err)
end
else error(err) end
return _return
end
--- Set function to run then an event is called on a thread, none of them are 'needed' but you are advised to have atleast one
-- @usage thread:on_event('close',function) -- return true
-- events = ['close','timeout','tick','resolve','success','error']
-- if event is a number then it is asumed to be a game event
-- @tparam string event the name of the event that it is called on
-- @tparam function callback the function which is called on the event
-- @treturn table returns self so that there can be chained
--- Set function to run then an event is triggered, none of them are 'needed' but you are advised to have atleast one
-- @usage thread:on_event('close',function) -- if event is not one below then a game event is used
-- @usage thread_only_events = ['close','timeout','tick','resolve','success','error']
-- @tparam ?string|index event the name of the event that the function should be called on
-- @tparam function callback the function which is called by the event trigger
-- @treturn table returns self so that they can be chained together
function Server._thread:on_event(event,callback)
local events = {'close','timeout','tick','resolve','success','error'}
-- seaches the above list for the event
local value = table.find(events,function(v,k,find) return v == string.lower(find) end,event)
if value and is_type(callback,'function') then
-- if it is a thread_only_event then it will add it to its core values
self['_'..value] = callback
elseif is_type(event,'number') and is_type(callback,'function') then
-- other wise it is appended to the event index of the thread
if not self._events then self._events = {} end
self._events[event] = callback
end
-- returns self to allowing chaining of on_event():on_event():on_event() etc..
return self
end
Event.register(defines.events.on_tick,function(event)
script.on_event(defines.events.on_tick,function(event)
-- uses its own on_tick event so that other actions can be tested for
if event.tick < 10 then return end
local threads = Server._threads()
if #threads.tick > 0 then Server.run_tick_threads() end
if #threads.timeout > 0 then Server.check_timeouts() end
if #threads.queue > 0 then
local current_thread = threads.all[threads.queue[1]]
if #global.tick > 0 then Server.run_tick_threads() end -- on tick events
if #global.timeout > 0 then Server.check_timeouts() end -- timeout checks
if #global.queue > 0 then -- resolve one thread
local current_thread = global.all[global.queue[1]]
if current_thread and current_thread:valid() then current_thread:resolve() end
end
end)
Event.register(-2,function(event)
local threads = Server.threads()
for uuid,thread in pairs(threads) do
if uuid ~= '_n' then setmetatable(thread,{__index=Server._thread}) end
end
script.on_event(-2,function(event)
-- sets up metatable again so that threads contiune to work
for uuid,thread in pairs(Server.threads) do setmetatable(thread,{__index=Server._thread}) end
end)
Server.on_init=function(self)
Event.register(defines.events,Server._thread_handler)
if pcall(function() return commands._expgaming end) then
commands.add_command('interface', 'Runs the given input from the script', {'code',true}, function(event,args)
local callback = args.code
if not string.find(callback,'%s') and not string.find(callback,'return') then callback = 'return '..callback end
if game.player then callback = 'local player, surface, force, position, entity, tile = game.player, game.player.surface, game.player.force, game.player.position, game.player.selected, game.player.surface.get_tile(game.player.position);'..callback end
if Ranking and Ranking.get_rank and game.player then callback = 'local rank = Ranking.get_rank(game.player);'..callback end
local success, err = Server.interface(callback)
if not success and is_type(err,'string') then local _end = string.find(err,'stack traceback') if _end then err = string.sub(err,0,_end-2) end end
if err or err == false then player_return(err) end
end)
end
if loaded_modules.commands then require(module_path..'/src/commands') end
end
return Server
--[[
Thread Example:
@@ -424,5 +473,22 @@ return Server
end)
thread:open()
all on_event functions can be chained from the thread creation rather than use varibles
all on_event functions can be chained from the thread creation rather than use varibles eg:
Server.new_thread{
name='tree-decon',
data={}
}:on_event('tick',function(self)
local trees = self.data
if #trees == 0 then return end
local tree = table.remove(trees,1)
if tree.valid then tree.destroy() end
end):on_event('error',function(self,err)
-- cant see how this can cause an error
-- but this is where error handling goes
-- any event including on_resolve and on_tick can raise this
end):on_event(defines.events.on_marked_for_deconstruction,function(self,event)
if event.entity.type == 'tree' then
table.insert(self.data,event.entity)
end
end):open()
]]

View File

@@ -0,0 +1,31 @@
--- Description - A small description that will be displayed on the doc
-- @submodule ExpGamingCore.Server
-- @alias Server
-- @author Cooldude2606
-- @license https://github.com/explosivegaming/scenario/blob/master/LICENSE
--- This file will be loaded when ExpGamingCore.Commands is present
-- @function _comment
commands.add_command('interface', 'Runs the given input from the script', {'code',true}, function(event,args)
local callback = args.code
-- looks for spaces, if non the it will prefix the command with return
if not string.find(callback,'%s') and not string.find(callback,'return') then callback = 'return '..callback end
-- sets up an env for the command to run in
local env = {_env=true,}
if game.player then
env.player = game.player
env.surface = game.player.surface
env.force = game.player.force
env.position = game.player.position
env.entity = game.player.selected
env.tile = game.player.surface.get_tile(game.player.position)
if Ranking and Ranking.get_rank then env.rank = Ranking.get_rank(game.player) end
end
-- runs the function
local success, err = Server.interface(callback,false,env)
-- if there is an error then it will remove the stacktrace and return the error
if not success and is_type(err,'string') then local _end = string.find(err,'stack traceback') if _end then err = string.sub(err,0,_end-2) end end
-- if there is a value returned that is not nill then it will return that value
if err or err == false then player_return(err) end
end)

View File

@@ -1,4 +1,4 @@
--- Description - A small description that will be displayed on the doc
--- Allows syncing with an outside server and info panle.
-- @module ExpGamingCore.Sync
-- @alias Sync
-- @author Cooldude2606
@@ -6,19 +6,28 @@
local Sync = {}
local Sync_updates = {}
-- sets up the global for this module
global{
server_name='Factorio Server',
server_description='A factorio server for everyone',
reset_time='On Demand',
time='Day Mth 00 00:00:00 UTC Year',
time_set={0,'0.00M'},
last_update={0,'0.00M'},
time_period={18000,'5.00M'},
players={online={'Offline'},n_online=0,all={'Offline'},n_all=0,admins_online=0,afk_players=0,times={'Offline'}},
ranks={'Offline'},
rockets=0,
mods={'Offline'}
--- Global Table
-- @table global
local global = global{
server_name='Factorio Server', -- the server name
server_description='A factorio server for everyone', -- a short description of the server
reset_time='On Demand', -- the reset time of the server
time='Day Mth 00 00:00:00 UTC Year', -- the last knowen irl time
time_set={0,'0.00M'}, -- the last in game time that the time was set
last_update={0,'0.00M'}, -- the last time that this info was updated
time_period={18000,'5.00M'}, -- how often this infomation is updated
players={
online={'Offline'}, -- list of all players online
n_online=0, -- the number of players online
all={'Offline'}, -- list of all player on or offline
n_all=0, -- the number of players who have joined the server
admins_online=0, -- the number of admins online
afk_players=0, -- the number of afk players
times={'Offline'} -- the play times of every player
}, -- a sub list of players in the game
ranks={'Offline'}, -- a list of player ranks
rockets=0, -- the number of rockets launched
mods={'Offline'} -- the mods which are loaded
}
--- Used to standidise the tick format for any sync info

View File

@@ -4,7 +4,7 @@
-- @author Cooldude2606
-- @license https://github.com/explosivegaming/scenario/blob/master/LICENSE
--- This file will be loaded when ExpGamingCore/Gui is present
--- This file will be loaded when ExpGamingCore.Gui is present
-- @function _comment
local Sync_gui_functions = {}

View File

@@ -4,7 +4,7 @@
-- @author Cooldude2606
-- @license https://github.com/explosivegaming/scenario/blob/master/LICENSE
--- This file will be loaded when ExpGamingCore/Ranking is present
--- This file will be loaded when ExpGamingCore.Ranking is present
-- @function _comment
--- Used as a redirect to Ranking._base_preset that will set the rank given to a player apon joining

View File

@@ -52,6 +52,7 @@
"location": "url",
"dependencies": {
"ExpGamingLib": ">=3.0.0",
"FactorioStdLib.Table": ">=0.8.0",
"ExpGamingCore/Ranking": "?>=3.0.0",
"ExpGamingCore/Commands": "?>=3.0.0"
}

View File

@@ -1,17 +1,9 @@
--[[
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-----------------------------------------------------------
--- 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 module_verbose = false -- there is no verbose in this file so true will do nothing
local ExpLib = {}

View File

@@ -12,6 +12,6 @@ return {
--['Ranking']='/modules/ExpGamingCore/Ranking',
--['commands']='/modules/ExpGamingCore/Commands',
--['Gui']='/modules/ExpGamingCore/Gui',
--['Server']='/modules/ExpGamingCore/Server',
['Server']='/modules/ExpGamingCore/Server',
['Sync']='/modules/ExpGamingCore/Sync',
}