Added Module: ExpGamingCore

This commit is contained in:
Cooldude2606
2018-05-30 13:50:38 +01:00
parent eeb44c0c93
commit 24598e594a
33 changed files with 250 additions and 189 deletions

View File

@@ -0,0 +1,151 @@
--[[
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 command_calls = {}
local command_data = {}
--- Uses a commands data to return the inputs as a string
-- @usage command = command_data[command_name]
-- command_inputs(command) -- returns "<input1> <input2> "
-- @tparam table the data for the command being run
-- @treturn string the inputs in string format
local function command_inputs(command)
if not is_type(command,'table') then return end
local inputs = ''
for _,input in pairs(command.inputs) do
if input == true then break end
inputs = inputs..'<'..input..'> '
end
return inputs
end
--- Uses the command data and the event to return a table of the args
-- @usage command = command_data[command_name]
-- command_args(event,command) -- return {input1='one',input2='two'}
-- @tparam defines.events.on_console_command event the event rasied by the command
-- @tparam table command the data for the command being run
-- @treturn table a table version of the event.parameter based on expected inputs
local function command_args(event,command)
if not event or not is_type(command,'table') then return end
local args = {}
-- haddles no parameters given
if not event.parameter then
if #command.inputs > 0 then return args, false
else return args, true
end
end
-- finds all the words and cheaks if the right number were given
local words = string.split(event.parameter,' ')
if table.last(command.inputs) == true then
if #words < #command.inputs-1 then return args, false end
else
if #words < #command.inputs then return args, false end
end
-- if it is the right number then process and return the args
for index,input in pairs(command.inputs) do
if command.inputs[index+1] == true then
args[input] = table.concat(words,' ',index)
break
else
args[input] = words[index]
end
end
return args, true
end
--- Used to return all the commands a player can use
-- @usage get_commands(1) -- return {{command data},{command data}}
-- @param player the player refreced by string|number|LuaPlayer|event
-- @treturn table a table containg all the commands the player can use
function commands.get_commands(player)
local commands = {}
local player = Game.get_player(player)
if not player then return commands end
local rank = Ranking.get_rank(player)
for name,data in pairs(command_data) do
if rank:allowed(name) then table.insert(commands,data) end
end
return commands
end
--- Used to call the custom commands
-- @usage You dont its an internal command
-- @tparam defines.events.on_console_command command the event rasied by the command
local function run_custom_command(command)
local command_data = command_data[command.name]
local player_name = Game.get_player(command) and Game.get_player(command).name or 'server'
-- is the player allowed to use this command
if is_type(Ranking,'table') and Ranking._presets and Ranking._presets().meta.rank_count > 0 and not Ranking.get_rank(player_name):allowed(command.name) then
player_return({'commands.unauthorized'},defines.textcolor.crit)
if game.player then game.player.play_sound{path='utility/cannot_build'} end
game.write_file('commands.log',
game.tick
..' Player: "'..player_name..'"'
..' Failed to use command (Unauthorized): "'..command.name..'"'
..' With args of: '..table.tostring(command_args(command,command_data))
..'\n'
, true, 0)
return
end
-- gets the args for the command
local args, valid = command_args(command,command_data)
if not valid then
player_return({'commands.invalid-inputs',command.name,command_inputs(command_data)},defines.textcolor.high)
if game.player then game.player.play_sound{path='utility/deconstruct_big'} end
game.write_file('commands.log',
game.tick
..' Player: "'..player_name..'"'
..' Failed to use command (Invalid Args): "'..command.name..'"'
..' With args of: '..table.tostring(args)
..'\n'
, true, 0)
return
end
-- runs the command
local success, err = pcall(command_calls[command.name],command,args)
if not success then error(err) end
if err ~= commands.error and player_name ~= 'server' then player_return({'commands.command-ran'},defines.textcolor.info) end
game.write_file('commands.log',
game.tick
..' Player: "'..player_name..'"'
..' Used command: "'..command.name..'"'
..' With args of: '..table.tostring(args)
..'\n'
, true, 0)
end
-- this is a set of constants you can use
commands._add_command = commands.add_command --if you dont want to use the custom commands interface
commands.expgaming = true --if you want to test if the custom commands are present
commands.error = {} --if returned during a custom command, Command Complete message not printed
--- Used to define commands
-- @usage inputs = {'player','reason',true}
-- commands.add_command('ban','bans a player',inputs,function() return end)
-- @tparam string name the name of the command
-- @tparam[opt='No Description'] string description the description of the command
-- @tparam[opt={'parameter',true}] table inputs a table of the inputs to be used, last index being true makes the last parameter open ended (longer than one word)
-- @tparam function event the function to call on the event
commands.add_command = function(name, description, inputs, event)
if command_calls[name] then return end
if not is_type(name,'string') then return end
if not is_type(event,'function') then return end
verbose('Created Command: '..name)
local description = is_type(description,'string') and description or 'No Description'
local inputs = is_type(inputs,'table') and inputs or {'parameter',true}
command_data[name] = {
name=name,
description=description,
inputs=inputs
}
command_calls[name] = event
commands._add_command(name,command_inputs(command_data[name])..'- '..description,function(...)
local success, err = pcall(run_custom_command,...)
if not success then error(err) end
end)
end

View File

@@ -0,0 +1,209 @@
--[[
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
]]
local center = {}
center._center = {}
--- Adds a new obj to the center gui
-- @usage Gui.center.add{name='foo',caption='Foo',tooltip='Testing',draw=function}
-- @param obj contains the new object, needs name, fraw is opt and is function(root_frame)
-- @return the object made, used to add tabs
function center.add(obj)
if not is_type(obj,'table') then return end
if not is_type(obj.name,'string') then return end
verbose('Created Center Gui: '..obj.name)
setmetatable(obj,{__index=center._center})
obj.tabs = {}
obj._tabs = {}
Gui._add_data('center',obj.name,obj)
Gui.toolbar.add(obj.name,obj.caption,obj.tooltip,obj.open)
return obj
end
--- Used to get the center frame of the player, used mainly in script
-- @usage Gui.center.get_flow(player) -- returns gui emelemt
-- @param player a player indifier to get the flow for
-- @treturn table the gui element flow
function center.get_flow(player)
local player = Game.get_player(player)
return player.gui.center.exp_center or player.gui.center.add{name='exp_center',type='flow'}
end
--- Used to open a center frame for a player
-- @usage Gui.center.open(player,'server-info') -- return true
-- @param player a player indifier to get the flow for
-- @tparam string center the name of the center frame to open
-- @treturn boelon based on if it successed or not
function center.open(player,center)
local player = Game.get_player(player)
Gui.center.clear(player)
if not Gui._get_data('center')[center] then return false end
Gui._get_data('center')[center].open{
element={name=center},
player_index=player.index
}
return true
end
--- Used to open a center frame for a player
-- @usage Gui.center.open_tab(player,'readme','rules') -- return true
-- @param player a player indifier to get the flow for
-- @tparam string center the name of the center frame to open
-- @tparam string tab the name of the tab to open
-- @treturn boelon based on if it successed or not
function center.open_tab(player,center,tab)
local player = Game.get_player(player)
if not Gui.center.open(player,center) then return false end
local name = center..'_'..tab
if not Gui._get_data('inputs_button')[name] then return false end
Gui._get_data('inputs_button')[name].events[defines.events.on_gui_click]{
element=Gui.center.get_flow(player)[center].tab_bar.tab_bar_scroll.tab_bar_scroll_flow[name],
}
return true
end
--- Used to clear the center frame of the player, used mainly in script
-- @usage Gui.center.clear(player)
-- @param player a player indifier to get the flow for
function center.clear(player)
local player = Game.get_player(player)
center.get_flow(player).clear()
end
-- used on the button press when the toolbar button is press, can be overriden
-- not recomented for direct use see Gui.center.open
function center._center.open(event)
local player = Game.get_player(event)
local _center = Gui._get_data('center')[event.element.name]
local center_flow = center.get_flow(player)
if center_flow[_center.name] then Gui.center.clear(player) return end
local center_frame = center_flow.add{
name=_center.name,
type='frame',
caption=_center.caption,
direction='vertical',
style=mod_gui.frame_style
}
if is_type(center_frame.caption,'string') and player.gui.is_valid_sprite_path(center_frame.caption) then center_frame.caption = '' end
if is_type(_center.draw,'function') then
local success, err = pcall(_center.draw,_center,center_frame)
if not success then error(err) end
else error('No Callback on center frame '.._center.name)
end
player.opened=center_frame
end
-- this is the default draw function if one is not provided, can be overriden
-- not recomented for direct use see Gui.center.open
function center._center:draw(frame)
Gui.bar(frame,510)
local tab_bar = frame.add{
type='frame',
name='tab_bar',
style='image_frame',
direction='vertical'
}
tab_bar.style.width = 510
tab_bar.style.height = 65
local tab_bar_scroll = tab_bar.add{
type='scroll-pane',
name='tab_bar_scroll',
horizontal_scroll_policy='auto-and-reserve-space',
vertical_scroll_policy='never'
}
tab_bar_scroll.style.vertically_squashable = false
tab_bar_scroll.style.vertically_stretchable = true
tab_bar_scroll.style.width = 500
local tab_bar_scroll_flow = tab_bar_scroll.add{
type='flow',
name='tab_bar_scroll_flow',
direction='horizontal'
}
Gui.bar(frame,510)
local tab = frame.add{
type ='frame',
name='tab',
direction='vertical',
style='image_frame'
}
tab.style.width = 510
tab.style.height = 305
local tab_scroll = tab.add{
type ='scroll-pane',
name='tab_scroll',
horizontal_scroll_policy='never',
vertical_scroll_policy='auto'
}
tab_scroll.style.vertically_squashable = false
tab_scroll.style.vertically_stretchable = true
tab_scroll.style.width = 500
local tab_scroll_flow = tab_scroll.add{
type='flow',
name='tab_scroll_flow',
direction='vertical'
}
tab_scroll_flow.style.width = 480
Gui.bar(frame,510)
local first_tab = nil
for name,button in pairs(self.tabs) do
first_tab = first_tab or name
button:draw(tab_bar_scroll_flow).style.font_color = defines.color.white
end
self._tabs[self.name..'_'..first_tab](tab_scroll_flow)
tab_bar_scroll_flow.children[1].style.font_color = defines.color.orange
frame.parent.add{type='frame',name='temp'}.destroy()--recenter the GUI
end
--- If deafult draw is used then you can add tabs to the gui with this function
-- @usage _center:add_tab('foo','Foo','Just a tab',function)
-- @tparam string name this is the name of the tab
-- @tparam string caption this is the words that appear on the tab button
-- @tparam[opt] string tooltip the tooltip that is on the button
-- @tparam function callback this is called when button is pressed with function(root_frame)
-- @return self to allow chaining of _center:add_tab
function center._center:add_tab(name,caption,tooltip,callback)
verbose('Created Tab: '..self.name..'/'..name)
self._tabs[self.name..'_'..name] = callback
self.tabs[name] = Gui.inputs.add{
type='button',
name=self.name..'_'..name,
caption=caption,
tooltip=tooltip
}:on_event('click',function(event)
local tab = event.element.parent.parent.parent.parent.tab.tab_scroll.tab_scroll_flow
tab.clear()
local frame_name = tab.parent.parent.parent.name
local _center = Gui._get_data('center')[frame_name]
local _tab = _center._tabs[event.element.name]
if is_type(_tab,'function') then
for _,button in pairs(event.element.parent.children) do
if button.name == event.element.name then
button.style.font_color = defines.color.orange
else
button.style.font_color = defines.color.white
end
end
local success, err = pcall(_tab,tab)
if not success then error(err) end
end
end)
return self
end
-- used so that when gui close key is pressed this will close the gui
Event.register(defines.events.on_gui_closed,function(event)
if event.element and event.element.valid then event.element.destroy() end
end)
-- when the player rank is changed it closses the center guis
if defines.events.rank_change then
Event.register(defines.events.rank_change,center.clear)
end
return center

View File

@@ -0,0 +1,375 @@
--[[
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
]]
local inputs = {}
inputs._input = {}
-- these are just so you can have short cuts to this
inputs.events = {
error='error',
state=defines.events.on_gui_checked_state_changed,
click=defines.events.on_gui_click,
elem=defines.events.on_gui_elem_changed,
selection=defines.events.on_gui_selection_state_changed,
text=defines.events.on_gui_text_changed,
slider=defines.events.on_gui_value_changed
}
--- Sets the input to trigger on an certain event
-- @usage button:on_event(defines.events.on_gui_click,player_return)
-- @param event the event to raise callback on | can be number of the event | can be a key of inputs.events
-- @tparam function callback the function you want to run on the event
-- @treturn table returns self so you can chain together
function inputs._input:on_event(event,callback)
if not is_type(callback,'function') then return self end
if inputs.events[event] then event = inputs.events[event] end
if event == 'error' then self._error = callback return self end
self.events[event] = callback
return self
end
--- Draw the input into the root element
-- @usage button:draw(frame)
-- @param root the element you want to add the input to
-- @return returns the element that was added
function inputs._input:draw(root)
local player = Game.get_player(root.player_index)
if is_type(self.draw_data.caption,'string') and player.gui.is_valid_sprite_path(self.draw_data.caption) then
local data = table.deepcopy(self.draw_data)
data.type = 'sprite-button'
data.sprite = data.caption
data.caption = nil
return root.add(data)
elseif is_type(self.draw_data.sprite,'string') and player.gui.is_valid_sprite_path(self.draw_data.sprite) then
local data = table.deepcopy(self.draw_data)
data.type = 'sprite-button'
return root.add(data)
elseif is_type(self.data._state,'function') then
local data = table.deepcopy(self.draw_data)
local success, err = pcall(self.data._state,player,root)
if success then data.state = err else error(err) end
return root.add(data)
elseif is_type(self.data._start,'function') then
local data = table.deepcopy(self.draw_data)
local success, err = pcall(self.data._start,player,root)
if success then data.value = err else error(err) end
return root.add(data)
elseif is_type(self.data._index,'function') then
local data = table.deepcopy(self.draw_data)
local success, err = pcall(self.data._index,player,root)
if success then data.selected_index = err else error(err) end
if is_type(self.data._items,'function') then
local success, err = pcall(self.data._items,player,root)
if success then data.items = err else error(err) end
end
return root.add(data)
elseif is_type(self.data._items,'function') then
local data = table.deepcopy(self.draw_data)
local success, err = pcall(self.data._items,player,root)
if success then data.items = err else error(err) end
if is_type(self.data._index,'function') then
local success, err = pcall(self.data._index,player,root)
if success then data.selected_index = err else error(err) end
end
return root.add(data)
else
return root.add(self.draw_data)
end
end
--- Add a new input, this is the same as doing frame.add{} but returns a diffrent object
-- @usage Gui.inputs.add{type='button',name='test',caption='Test'}
-- @tparam table obj the new element to add if caption is a sprite path then sprite is used
-- @treturn table the custom input object
function inputs.add(obj)
if not is_type(obj,'table') then return end
if not is_type(obj.type,'string') then return end
local type = obj.type
if type == 'button' or
type == 'sprite-button' or
type == 'choose-elem-button' or
type == 'checkbox' or
type == 'radiobutton' or
type == 'textfield' or
type == 'text-box' or
type == 'slider' or
type == 'drop-down'
then else return end
verbose('Created Input: '..obj.name..' ('..obj.type..')')
if obj.type == 'button' or obj.type == 'sprite-button' then obj.style = mod_gui.button_style end
obj.draw_data = table.deepcopy(obj)
obj.data = {}
obj.events = {}
setmetatable(obj,{__index=inputs._input})
Gui._add_data('inputs_'..type,obj.name,obj)
return obj
end
-- this just runs the events given to inputs
function inputs._event_handler(event)
if not event.element then return end
local elements = Gui._get_data('inputs_'..event.element.type) or {}
local element = elements[event.element.name]
if not element and event.element.type == 'sprite-button' then
elements = Gui._get_data('inputs_button') or {}
element = elements[event.element.name]
end
if element then
if not is_type(element.events[event.name],'function') then return end
local success, err = pcall(element.events[event.name],event)
if not success then
if is_type(element._error,'function') then pcall(element._error)
else error(err) end
end
end
end
Event.register(inputs.events.state,inputs._event_handler)
Event.register(inputs.events.click,inputs._event_handler)
Event.register(inputs.events.elem,inputs._event_handler)
Event.register(inputs.events.state,inputs._event_handler)
Event.register(inputs.events.text,inputs._event_handler)
Event.register(inputs.events.slider,inputs._event_handler)
Event.register(inputs.events.selection,inputs._event_handler)
-- the folwing functions are just to make inputs easier but if what you want is not include use inputs.add(obj)
--- Used to define a button, can have many function
-- @usage Gui.inputs.add_button('test','Test','Just for testing',{{condition,callback},...})
-- @tparam string name the name of this button
-- @tparam string the display for this button, either text or sprite path
-- @tparam string tooltip the tooltip to show on the button
-- @param callbacks can either be a single function or a list of function pairs see exaplmes at bottom
-- @treturn table the button object that was made, to allow a custom error event if wanted
function inputs.add_button(name,display,tooltip,callbacks)
local button = inputs.add{
type='button',
name=name,
caption=display,
tooltip=tooltip
}
button.data._callbacks = callbacks
button:on_event('click',function(event)
local elements = Gui._get_data('inputs_'..event.element.type) or {}
local button = elements[event.element.name]
if not button and event.element.type == 'sprite-button' then
elements = Gui._get_data('inputs_button') or {}
button = elements[event.element.name]
end
local player = Game.get_player(event)
local mouse = event.button
local keys = {alt=event.alt,ctrl=event.control,shift=event.shift}
local element = event.element
local callbacks = button.data._callbacks
if is_type(callbacks,'function') then callbacks = {{function(...) return true end,callbacks}} end
for _,data in pairs(callbacks) do
if is_type(data[1],'function') and is_type(data[2],'function') then
local success, err = pcall(data[1],player,mouse,keys,event)
if success and err == true then
local success, err = pcall(data[2],player,element,event)
if not success then error(err) end
elseif not success then error(err) end
else error('Invalid Callback Condition Format') end
end
end)
return button
end
--- Used to define a choose-elem-button callback only on elem_changed
-- @usage Gui.inputs.add_elem_button('test','Test','Just for testing',function)
-- @tparam string name the name of this button
-- @tparam string elem_type the display for this button, either text or sprite path
-- @tparam string tooltip the tooltip to show on the button
-- @tparam function callback the callback to call on change function(player,element,elem)
-- @treturn table the button object that was made, to allow a custom error event if wanted
function inputs.add_elem_button(name,elem_type,tooltip,callback)
local button = inputs.add{
type='choose-elem-button',
name=name,
elem_type=elem_type,
tooltip=tooltip
}
button.data._callback = callback
button:on_event('elem',function(event)
local button = Gui._get_data('inputs_'..event.element.type)[event.element.name]
local player = Game.get_player(event)
local element = event.element or {elem_type=nil,elem_value=nil}
local elem = {type=element.elem_type,value=element.elem_value}
if is_type(button.data._callback,'function') then
local success, err = pcall(button.data._callback,player,element,elem)
if not success then error(err) end
else error('Invalid Callback') end
end)
return button
end
--- Used to define a checkbox callback only on state_changed
-- @usage Gui.inputs.add_checkbox('test',false,'Just for testing',function,function,funvtion)
-- @tparam string name the name of this button
-- @tparam boolean radio if this is a radio button
-- @tparam string display the display for this button, either text or sprite path
-- @tparam function default the callback which choses the default check state
-- @tparam function callback_true the callback to call when changed to true
-- @tparam function callback_false the callback to call when changed to false
-- @treturn table the button object that was made, to allow a custom error event if wanted
function inputs.add_checkbox(name,radio,display,default,callback_true,callback_false)
local type = 'checkbox'; if radio then type='radiobutton' end
local state = false; if is_type(default,'boolean') then state = default end
local checkbox = inputs.add{
type=type,
name=name,
caption=display,
state=state
}
if is_type(default,'function') then checkbox.data._state = default end
checkbox.data._true = callback_true
checkbox.data._false = callback_false
checkbox:on_event('state',function(event)
local checkbox = Gui._get_data('inputs_'..event.element.type)[event.element.name]
local player = Game.get_player(event)
local state = event.element.state
if state then
if is_type(checkbox.data._true,'function') then
local success, err = pcall(checkbox.data._true,player,event.element)
if not success then error(err) end
else error('Invalid Callback') end
else
if is_type(checkbox.data._false,'function') then
local success, err = pcall(checkbox.data._false,player,event.element)
if not success then error(err) end
else error('Invalid Callback') end
end
end)
return checkbox
end
--- Used to reset the state of radio buttons, recomened to be called on_state_change to reset any radio buttons it is ment to work with.
-- @usage Gui.inputs.reset_radio{radio1,radio2,...}
-- @param elements can be a list of elements or a single element
function inputs.reset_radio(elements)
if #elements > 0 then
for _,element in pairs(elements) do
if element.valid then
local _elements = Gui._get_data('inputs_'..element.type) or {}
local _element = _elements[element.name]
local player = Game.get_player(element.player_index)
local state = false
local success, err = pcall(_element.data._state,player,element.parent)
if success then state = err else error(err) end
element.state = state
end
end
else
if elements.valid then
local _elements = Gui._get_data('inputs_'..elements.type) or {}
local _element = _elements[elements.name]
local player = Game.get_player(elements.player_index)
local state = false
local success, err = pcall(_element.data._state,player,elements.parent)
if success then state = err else error(err) end
elements.state = state
end
end
end
--- Used to define a text callback only on text_changed
-- @usage Gui.inputs.add_text('test',false,'Just for testing',function)
-- @tparam string name the name of this button
-- @tparam boolean box is it a text box rather than a text field
-- @tparam string text the starting text
-- @tparam function callback the callback to call on change function(player,text,element)
-- @treturn table the text object that was made, to allow a custom error event if wanted
function inputs.add_text(name,box,text,callback)
local type = 'textfield'; if box then type='text-box' end
local textbox = inputs.add{
type=type,
name=name,
text=text
}
textbox.data._callback = callback
textbox:on_event('text',function(event)
local textbox = Gui._get_data('inputs_'..event.element.type)[event.element.name]
local player = Game.get_player(event)
local element = event.element
local callback = textbox.data._callback
if is_type(callback,'function') then
local success, err = pcall(callback,player,element.text,element)
if not success then error(err) end
else error('Invalid Callback Condition Format') end
end)
return textbox
end
--- Used to define a slider callback only on value_changed
-- @usage Gui.inputs.add_slider('test','horizontal',1,10,5,function)
-- @tparam string name the name of this button
-- @tparam string orientation direction of the slider
-- @tparam number min the lowest number
-- @tparam number max the highest number
-- @tparam function start_callback either a number or a function to return a number
-- @tparam function callback the function to be called on value_changed function(player,value,percent,element)
-- @treturn table the slider object that was made, to allow a custom error event if wanted
function inputs.add_slider(name,orientation,min,max,start_callback,callback)
local slider = inputs.add{
type='slider',
name=name,
orientation=orientation,
minimum_value=min,
maximum_value=max,
value=start_callback
}
slider.data._start = start_callback
slider.data._callback = callback
slider:on_event('slider',function(event)
local slider = Gui._get_data('inputs_'..event.element.type)[event.element.name]
local player = Game.get_player(event)
local value = event.element.slider_value
local data = slider.data
local percent = value/event.element.get_slider_maximum()
if is_type(data._callback,'function') then
local success, err = pcall(data._callback,player,value,percent,event.element)
if not success then error(err) end
else error('Invalid Callback Condition Format') end
end)
return slider
end
--- Used to define a drop down callback only on value_changed
-- @usage Gui.inputs.add_drop_down('test',{1,2,3},1,function)
-- @tparam string name name of the drop down
-- @param items either a list or a function which returns a list
-- @param index either a number or a function which returns a number
-- @tparam function callback the callback which is called when a new index is selected function(player,selected,items,element)
-- @treturn table the drop-down object that was made, to allow a custom error event if wanted
function inputs.add_drop_down(name,items,index,callback)
local drop_down = inputs.add{
type='drop-down',
name=name,
items=items,
selected_index=index
}
drop_down.data._items = items
drop_down.data._index = index
drop_down.data._callback = callback
drop_down:on_event('selection',function(event)
local drop_down = Gui._get_data('inputs_'..event.element.type)[event.element.name]
local player = Game.get_player(event)
local element = event.element
local items = element.items
local selected = items[element.selected_index]
local callback = drop_down.data._callback
if is_type(callback,'function') then
local success, err = pcall(callback,player,selected,items,element)
if not success then error(err) end
else error('Invalid Callback Condition Format') end
end)
return drop_down
end
return inputs
-- to see examples look at GuiParts/test.lua

View File

@@ -0,0 +1,177 @@
--[[
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
]]
local left = {}
left._left = {}
-- used for debugging
function left.override_open(state)
Gui._global().over_ride_left_can_open = state
end
--- Used to add a left gui frame
-- @usage Gui.left.add{name='foo',caption='Foo',tooltip='just testing',open_on_join=true,can_open=function,draw=function}
-- @param obj this is what will be made, needs a name and a draw function(root_frame), open_on_join can be used to set the deaful state true/false, can_open is a test to block it from opening but is not needed
-- @return the object that is made to... well idk but for the future
function left.add(obj)
if not is_type(obj,'table') then return end
if not is_type(obj.name,'string') then return end
verbose('Created Left Gui: '..obj.name)
setmetatable(obj,{__index=left._left})
Gui._add_data('left',obj.name,obj)
Gui.toolbar.add(obj.name,obj.caption,obj.tooltip,obj.toggle)
return obj
end
--- This is used to update all the guis of conected players, good idea to use our thread system as it as nested for loops
-- @usage Gui.left.update()
-- @tparam[opt] string frame this is the name of a frame if you only want to update one
-- @param[opt] players the player to update for, if not given all players are updated, can be one player
function left.update(frame,players)
if not Server or not Server._thread then
local players = is_type(players,'table') and #players > 0 and {unpack(players)} or is_type(players,'table') and {players} or Game.get_player(players) and {Game.get_player(players)} or game.connected_players
for _,player in pairs(players) do
local frames = Gui._get_data('left') or {}
if frame then frames = {[frame]=frames[frame]} or {} end
for name,left in pairs(frames) do
if _left then
local fake_event = {player_index=player.index,element={name=name}}
left.open(fake_event)
end
end
end
else
local frames = Gui._get_data('left') or {}
if frame then frames = {[frame]=frames[frame]} or {} end
local players = is_type(players,'table') and #players > 0 and {unpack(players)} or is_type(players,'table') and {players} or Game.get_player(players) and {Game.get_player(players)} or game.connected_players
Server.new_thread{
data={players=players,frames=frames}
}:on_event('tick',function(thread)
if #thread.data.players == 0 then thread:close() return end
local player = table.remove(thread.data.players,1)
Server.new_thread{
data={player=player,frames=thread.data.frames}
}:on_event('resolve',function(thread)
for name,left in pairs(thread.data.frames) do
if left then
local fake_event = {player_index=thread.data.player.index,element={name=name}}
left.open(fake_event)
end
end
end):queue()
end):open()
end
end
--- Used to open the left gui of every player
-- @usage Gui.left.open('foo')
-- @tparam string left_name this is the gui that you want to open
function left.open(left_name)
local _left = Gui._get_data('left')[left_name]
if not _left then return end
if not Server or not Server._thread then
for _,player in pairs(game.connected_players) do
local left_flow = mod_gui.get_frame_flow(player)
if left_flow[_left.name] then left_flow[_left.name].style.visible = true end
end
else
Server.new_thread{
data={players=game.connected_players}
}:on_event('tick',function(thread)
if #thread.data.players == 0 then thread:close() return end
local player = table.remove(thread.data.players,1)
local left_flow = mod_gui.get_frame_flow(player)
if left_flow[_left.name] then left_flow[_left.name].style.visible = true end
end):open()
end
end
--- Used to close the left gui of every player
-- @usage Gui.left.close('foo')
-- @tparam string left_name this is the gui that you want to close
function left.close(left_name)
local _left = Gui._get_data('left')[left_name]
if not _left then return end
if not Server or not Server._thread then
for _,player in pairs(game.connected_players) do
local left_flow = mod_gui.get_frame_flow(player)
if left_flow[_left.name] then left_flow[_left.name].style.visible = false end
end
else
Server.new_thread{
data={players=game.connected_players}
}:on_event('tick',function(thread)
if #thread.data.players == 0 then thread:close() return end
local player = table.remove(thread.data.players,1)
local left_flow = mod_gui.get_frame_flow(player)
if left_flow[_left.name] then left_flow[_left.name].style.visible = false end
end):open()
end
end
-- this is used to draw the gui for the first time (these guis are never destoryed), used by the script
function left._left.open(event)
local player = Game.get_player(event)
local _left = Gui._get_data('left')[event.element.name]
local left_flow = mod_gui.get_frame_flow(player)
local frame = nil
if left_flow[_left.name] then
frame = left_flow[_left.name]
frame.clear()
else
frame = left_flow.add{type='frame',name=_left.name,style=mod_gui.frame_style,caption=_left.caption,direction='vertical'}
frame.style.visible = false
if is_type(_left.open_on_join,'boolean') then frame.style.visible = _left.open_on_join end
end
if is_type(_left.draw,'function') then _left.draw(frame) else frame.style.visible = false error('No Callback On '.._left.name) end
end
-- this is called when the toolbar button is pressed
function left._left.toggle(event)
local player = Game.get_player(event)
local _left = Gui._get_data('left')[event.element.name]
local left_flow = mod_gui.get_frame_flow(player)
if not left_flow[_left.name] then _left.open(event) end
local left = left_flow[_left.name]
local open = false
if is_type(_left.can_open,'function') then
local success, err = pcall(_left.can_open,player)
if not success then error(err)
elseif err == true then open = true
elseif Gui._global().over_ride_left_can_open then
if is_type(Ranking,'table') and Ranking._presets and Ranking._presets().meta.rank_count > 0 then
if Ranking.get_rank(player):allowed(_left.name) then open = true
else open = {gui.unauthorized} end
end
else open = err end
else
if is_type(Ranking,'table') and Ranking._presets and Ranking._presets().meta.rank_count > 0 then
if Ranking.get_rank(player):allowed(_left.name) then open = true
else open = {gui.unauthorized} end
end
end
if open == true and left.style.visible ~= true then
left.style.visible = true
else
left.style.visible = false
end
if open == false then player_return({'gui.cant-open-no-reason'},defines.textcolor.crit,player) player.play_sound{path='utility/cannot_build'}
elseif open ~= true then player_return({'gui.cant-open',open},defines.textcolor.crit,player) player.play_sound{path='utility/cannot_build'} end
end
-- draws the left guis when a player first joins, fake_event is just because i am lazy
Event.register(defines.events.on_player_joined_game,function(event)
local player = Game.get_player(event)
local frames = Gui._get_data('left') or {}
for name,left in pairs(frames) do
local fake_event = {player_index=player.index,element={name=name}}
left.open(fake_event)
end
end)
return left

View File

@@ -0,0 +1,112 @@
--[[
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
]]
local popup = {}
popup._popup = {}
function popup._load()
popup._popup.close = Gui.inputs.add{
type='button',
name='popup-close',
caption='utility/set_bar_slot',
tooltip='Close This Popup'
}:on_event('click',function(event)
local frame = event.element.parent
if frame and frame.valid then frame.destroy() end
end)
end
--- Used to add a popup gui style
-- @usage Gui.left.add{name='foo',caption='Foo',draw=function}
-- @param obj this is what will be made, needs a name and a draw function(root_frame,data)
-- @return the object that is made to... well idk but for the future
function popup.add(obj)
if not is_type(obj,'table') then return end
if not is_type(obj.name,'string') then return end
verbose('Created Popup Gui: '..obj.name)
setmetatable(obj,{__index=popup._popup})
local name = obj.name; obj.name = nil
Gui._add_data('popup',name,obj)
obj.name = name
return obj
end
-- this is used by the script to find the popup flow
function popup.flow(player)
local player = Game.get_player(player)
local flow = mod_gui.get_frame_flow(player).popups or mod_gui.get_frame_flow(player).add{name='popups',type='flow',direction='vertical'}
return flow
end
--- Use to open a popup for these players
-- @usage Gui.popup.open('ban',nil,{player=1,reason='foo'})
-- @tparam string style this is the name you gave to the popup when added
-- @param data this is the data that is sent to the draw function
-- @tparam[opt=game.connected_players] table players the players to open the popup for
function popup.open(style,data,players)
local _popup = Gui._get_data('popup')[style]
local players = players or game.connected_players
local data = data or {}
if not _popup then return end
if _popup.left then Gui.left.close(_popup.left.name) end
if not Server or not Server._thread then
for _,player in pairs(players) do
local flow = popup.flow(player)
local _frame = flow.add{
type='frame',
direction='horizontal',
style=mod_gui.frame_style
}
local frame = _frame.add{
type='frame',
name='inner_frame',
direction='vertical',
style='image_frame'
}
_popup.close:draw(_frame)
if is_type(_popup.draw,'function') then
local success, err = pcall(_popup.draw,frame,data)
if not success then error(err) end
else error('No Draw On Popup '.._popup.name) end
end
else
Server.new_thread{
data={players=players,popup=_popup,data=data}
}:on_event('tick',function(thread)
if #thread.data.players == 0 then thread:close() return end
local player = table.remove(thread.data.players,1)
local flow = popup.flow(player)
local _frame = flow.add{
type='frame',
direction='horizontal',
style=mod_gui.frame_style
}
local frame = _frame.add{
type='frame',
name='inner_frame',
direction='vertical',
style='image_frame'
}
thread.data.popup.close:draw(_frame)
if is_type(thread.data.popup.draw,'function') then
local success, err = pcall(thread.data.popup.draw,frame,thread.data.data)
if not success then error(err) end
else error('No Draw On Popup '..thread.data.popup.name) end
end):open()
end
end
function popup._popup:add_left(obj)
obj.name = obj.name or self.name
self.left = Gui.left.add(obj)
end
Event.register(defines.events.on_player_joined_game,popup.flow)
return popup

View File

@@ -0,0 +1,173 @@
-- this is just testing all the diffrent inputs to open test use /c Gui.test()
local gui_tset_close = Gui.inputs.add{
name='gui-test-close',
type='button',
caption='Close Test Gui'
}:on_event('click',function(event) event.element.parent.destroy() end)
local caption_test = Gui.inputs.add{
name='text-button',
type='button',
caption='Test'
}:on_event('click',function(event) game.print('test') end)
local sprite_test = Gui.inputs.add{
name='sprite-button',
type='button',
sprite='item/lab'
}:on_event('click',function(event) game.print('test') end)
local input_test = Gui.inputs.add_button('test-inputs','Try RMB','alt,ctrl,shift and mouse buttons',{
{
function(player,mouse,keys) return mouse == defines.mouse_button_type.left and keys.alt end,
function(player,element) player_return('Left: Alt',nil,player) end
},
{
function(player,mouse,keys) return mouse == defines.mouse_button_type.left and keys.ctrl end,
function(player,element) player_return('Left: Ctrl',nil,player) end
},
{
function(player,mouse,keys) return mouse == defines.mouse_button_type.left and keys.shift end,
function(player,element) player_return('Left: Shift',nil,player) end
},
{
function(player,mouse,keys) return mouse == defines.mouse_button_type.right and keys.alt end,
function(player,element) player_return('Right: Alt',nil,player) end
},
{
function(player,mouse,keys) return mouse == defines.mouse_button_type.right and keys.ctrl end,
function(player,element) player_return('Right: Ctrl',nil,player) end
},
{
function(player,mouse,keys) return mouse == defines.mouse_button_type.right and keys.shift end,
function(player,element) player_return('Right: Shift',nil,player) end
}
}):on_event('error',function(err) game.print('this is error handliling') end)
local elem_test = Gui.inputs.add_elem_button('test-elem','item','Testing Elems',function(player,element,elem)
player_return(elem.type..' '..elem.value,nil,player)
end)
local check_test = Gui.inputs.add_checkbox('test-check',false,'Cheat Mode',function(player,parent)
return game.players[parent.player_index].cheat_mode
end,function(player,element)
player.cheat_mode = true
end,function(player,element)
player.cheat_mode = false
end)
local radio_test = Gui.inputs.add_checkbox('test-radio',true,'Kill Self',function(player,parent)
return false
end,function(player,element)
if player.character then player.character.die() end
Gui.inputs.reset_radio(element.parent['test-radio-reset'])
end)
local radio_test_reset = Gui.inputs.add_checkbox('test-radio-reset',true,'Reset Kill Self',function(player,parent)
return not parent['test-radio'].state
end,function(player,element)
Gui.inputs.reset_radio(element.parent['test-radio'])
end)
local text_test = Gui.inputs.add_text('test-text',false,'default text',function(player,text,element)
player_return(text,nil,player)
end)
local box_test = Gui.inputs.add_text('test-box',true,'default text but a box',function(player,text,element)
player_return(text,nil,player)
end)
local slider_test = Gui.inputs.add_slider('test-slider','vertical',0,5,function(player,parent)
return player.character_running_speed_modifier
end,function(player,value,percent,element)
player.character_running_speed_modifier = value
player_return('Value In Percent of Max '..math.floor(percent*100)-(math.floor(percent*100)%5),nil,player)
end)
local drop_test = Gui.inputs.add_drop_down('test-drop',table.keys(defines.color),1,function(player,selected,items,element)
player.color = defines.color[selected]
player.chat_color = defines.color[selected]
end)
local function test_gui(event)
if not game.player and not event.player_index then return end
local player = game.player or Game.get_player(event)
if mod_gui.get_frame_flow(player)['gui-test'] then mod_gui.get_frame_flow(player)['gui-test'].destroy() end
local frame = mod_gui.get_frame_flow(player).add{type='frame',name='gui-test',direction='vertical'}
gui_tset_close:draw(frame)
caption_test:draw(frame)
sprite_test:draw(frame)
input_test:draw(frame)
elem_test:draw(frame)
check_test:draw(frame)
radio_test:draw(frame)
radio_test_reset:draw(frame)
text_test:draw(frame)
box_test:draw(frame)
slider_test:draw(frame)
drop_test:draw(frame)
end
Gui.toolbar.add('open-gui-test','Open Test Gui','Opens the test gui with every input',test_gui)
-- testing the center gui
Gui.center.add{
name='test-center',
caption='Gui Center',
tooltip='Just a gui test'
}:add_tab('tab-1','Tab 1','Just a tab',function(frame)
frame.add{type='label',caption='Test'}
end):add_tab('tab-2','Tab 2','Just a tab',function(frame)
for i = 1,100 do
frame.add{type='label',caption='Test 2'}
end
end)
-- testing the left gui
Gui.left.add{
name='test-left',
caption='Gui Left',
tooltip='just testing',
draw=function(frame)
for _,player in pairs(game.connected_players) do
frame.add{type='label',caption=player.name}
end
end,
can_open=function(player) return player.index == 1 end
}
local text_popup = Gui.inputs.add_text('test-popup-text',true,'Message To Send',function(player,text,element)
element.text = text
end)
local send_popup = Gui.inputs.add{
type='button',
name='test-popup-send',
caption='Send Message'
}:on_event('click',function(event)
local player = Game.get_player(event)
local message = event.element.parent['test-popup-text'].text
Gui.popup.open('test-popup',{player=player.name,message=message})
end)
Gui.popup.add{
name='test-popup',
caption='Gui Popup',
draw=function(frame,data)
frame.add{type='label',caption='Opened by: '..data.player}
frame.add{type='label',caption='Message: '..data.message}
end
}:add_left{
caption='Gui Left w/ Popup',
tooltip='Send a message',
draw=function(frame)
text_popup:draw(frame)
send_popup:draw(frame)
end
}
return test_gui

View File

@@ -0,0 +1,51 @@
--[[
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
]]
local toolbar = {}
--- Add a button to the toolbar, ranks need to be allowed to use these buttons if ranks is preset
-- @usage toolbar.add('foo','Foo','Test',function() game.print('test') end)
-- @tparam string name the name of the button
-- @tparam string caption can be a sprite path or text to show
-- @tparam string tooltip the help to show for the button
-- @tparam function callback the function which is called on_click
-- @treturn table the button object that was made
function toolbar.add(name,caption,tooltip,callback)
verbose('Created Toolbar Button: '..name)
local button = Gui.inputs.add{type='button',name=name,caption=caption,tooltip=tooltip}
button:on_event(Gui.inputs.events.click,callback)
Gui._add_data('toolbar',name,button)
return button
end
--- Draws the toolbar for a certain player
-- @usage toolbar.draw(1)
-- @param player the player to draw the tool bar of
function toolbar.draw(player)
local player = Game.get_player(player)
if not player then return end
local toolbar_frame = mod_gui.get_button_flow(player)
toolbar_frame.clear()
if not Gui._get_data('toolbar') then return end
for name,button in pairs(Gui._get_data('toolbar')) do
if is_type(Ranking,'table') and Ranking._presets and Ranking._presets().meta.rank_count > 0 then
local rank = Ranking.get_rank(player)
if rank:allowed(name) then
button:draw(toolbar_frame)
end
else button:draw(toolbar_frame) end
end
end
if defines.events.rank_change then
Event.register(defines.events.rank_change,toolbar.draw)
end
Event.register(defines.events.on_player_joined_game,toolbar.draw)
return toolbar

View File

@@ -0,0 +1,188 @@
--[[
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
]]
local Gui = {}
local Gui_data = {}
-- only really used when parts of expcore are missing, or script debuging (ie to store the location of frames)
function Gui._global(reset)
global.exp_core = not reset and global.exp_core or {}
global.exp_core.gui = not reset and global.exp_core.gui or {}
return global.exp_core.gui
end
-- this is to enforce the read only propetry of the gui
function Gui._add_data(key,value_key,value)
if game then return end
if not Gui_data[key] then Gui_data[key] = {} end
Gui_data[key][value_key] = value
end
function Gui._get_data(key) return Gui_data[key] end
Gui.center = require(module_path..'/GuiParts/center')
Gui.inputs = require(module_path..'/GuiParts/inputs')
Gui.left = require(module_path..'/GuiParts/left')
Gui.popup = require(module_path..'/GuiParts/popup')
Gui.toolbar = require(module_path..'/GuiParts/toolbar')
--- Add a white bar to any gui frame
-- @usage Gui.bar(frame,100)
-- @param frame the frame to draw the line to
-- @param[opt=10] width the width of the bar
-- @return the line that was made type is progressbar
function Gui.bar(frame,width)
local line = frame.add{
type='progressbar',
size=1,
value=1
}
line.style.height = 3
line.style.width = width or 10
line.style.color = defines.color.white
return line
end
--- Used to set the index of a drop down to a certian item
-- @usage Gui.set_dropdown_index(dropdown,player.name)
-- @param dropdown the dropdown that is to be effected
-- @param _item this is the item to look for
-- @return returns the dropdown if it was successful
function Gui.set_dropdown_index(dropdown,_item)
if dropdown and dropdown.valid and dropdown.items and _item then else return end
local _index = 1
for index, item in pairs(dropdown.items) do
if item == _item then _index = index break end
end
dropdown.selected_index = _index
return dropdown
end
Gui.on_init=function(self)
Gui.test = require(module_path..'/GuiParts/test')
if not Server then return end
Event.register(-1,function(event)
Server.new_thread{
name='camera-follow',
data={cams={},cam_index=1,players={}}
}:on_event('tick',function(self)
local _cam = self.data.cams[self.data.cam_index]
if not _cam then self.data.cam_index = 1 _cam = self.data.cams[self.data.cam_index] end
if not _cam then return end
if not _cam.cam.valid then table.remove(self.data.cams,self.data.cam_index)
elseif not _cam.entity.valid then table.remove(self.data.cams,self.data.cam_index)
else _cam.cam.position = _cam.entity.position if not _cam.surface then _cam.cam.surface_index = _cam.entity.surface.index end self.data.cam_index = self.data.cam_index+1
end
end):on_event('error',function(self,err)
-- posible error handling if needed
error(err)
end):on_event(defines.events.on_player_respawned,function(self,event)
if self.data.players[event.player_index] then
local remove = {}
for index,cam in pairs(self.data.players[event.player_index]) do
Gui.cam_link{cam=cam,entity=Game.get_player(event).character}
if not cam.valid then table.insert(remove,index) end
end
for _,index in pairs(remove) do
table.remove(self.data.players[event.player_index],index)
end
end
end):open()
end)
end
--- Adds a camera that updates every tick (or less depeading on how many are opening) it will move to follow an entity
-- @usage Gui.cam_link{entity=game.player.character,frame=frame,width=50,hight=50,zoom=1}
-- @usage Gui.cam_link{entity=game.player.character,cam=frame.camera,surface=game.surfaces['testing']}
-- @tparam table data contains all other params given below
-- @field entity this is the entity that the camera will follow
-- @field cam a camera that you already have in the gui
-- @field frame the frame to add the camera to, no effect if cam param is given
-- @field zoom the zoom to give the new camera
-- @field width the width to give the new camera
-- @field height the height to give the new camera
-- @field surface this will over ride the surface that the camera follows on, allowing for a 'ghost surface' while keeping same position
-- @field respawn_open if set to true then the camera will auto re link to the player after a respawn
-- @return the camera that the function used be it made or given as a param
function Gui.cam_link(data)
if not data.entity or not data.entity.valid then return end
if is_type(data.cam,'table') and data.cam.__self and data.cam.valid then
data.cam = data.cam
elseif data.frame then
data.cam={}
data.cam.type='camera'
data.cam.name='camera'
data.cam.position= data.entity.position
data.cam.surface_index= data.surface and data.surface.index or data.entity.surface.index
data.cam.zomm = data.zoom
data.cam = data.frame.add(data.cam)
data.cam.style.width = data.width or 100
data.cam.style.height = data.height or 100
else return end
if not Server or not Server._thread or not Server.get_thread('camera-follow') then
if not Gui._global().cams then
Gui._global().cams = {}
Gui._global().cam_index = 1
end
if data.cam then
local surface = data.surface and data.surface.index or nil
table.insert(Gui._global().cams,{cam=data.cam,entity=data.entity,surface=surface})
end
if not Gui._global().players then
Gui._global().players = {}
end
if data.respawn_open then
if data.entity.player then
if not Gui._global().players[data.entity.player.index] then Gui._global().players[data.entity.player.index] = {} end
table.insert(Gui._global().players[data.entity.player.index],data.cam)
end
end
else
local thread = Server.get_thread('camera-follow')
local surface = data.surface and data.surface.index or nil
table.insert(thread.data.cams,{cam=data.cam,entity=data.entity,surface=surface})
if data.respawn_open then
if data.entity.player then
if not thread.data.players[data.entity.player.index] then thread.data.players[data.entity.player.index] = {} end
table.insert(thread.data.players[data.entity.player.index],data.cam)
end
end
end
return data.cam
end
Event.register(defines.events.on_tick, function(event)
if Gui.left and ((event.tick+10)/(3600*game.speed)) % 15 == 0 then
Gui.left.update()
end
if Gui._global().cams and is_type(Gui._global().cams,'table') and #Gui._global().cams > 0 then
local _cam = Gui._global().cams[Gui._global().cam_index]
if not _cam then Gui._global().cam_index = 1 _cam = Gui._global().cams[Gui._global().cam_index] end
if not _cam then return end
if not _cam.cam.valid then table.remove(Gui._global().cams,Gui._global().cam_index)
elseif not _cam.entity.valid then table.remove(Gui._global().cams,Gui._global().cam_index)
else _cam.cam.position = _cam.entity.position if not _cam.surface then _cam.cam.surface_index = _cam.entity.surface.index end Gui._global().cam_index = Gui._global().cam_index+1
end
end
end)
Event.register(defines.events.on_player_respawned,function(event)
if Gui._global().players and is_type(Gui._global().players,'table') and #Gui._global().players > 0 and Gui._global().players[event.player_index] then
local remove = {}
for index,cam in pairs(Gui._global().players[event.player_index]) do
Gui.cam_link{cam=cam,entity=Game.get_player(event).character}
if not cam.valid then table.insert(remove,index) end
end
for _,index in pairs(remove) do
table.remove(Gui._global().players[event.player_index],index)
end
end
end)
return Gui

View File

@@ -0,0 +1,230 @@
--[[
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 groups = {}
local ranks = {}
function Ranking._add_group(group) if game then return end table.insert(groups,group) end
function Ranking._add_rank(rank,pos) if game then return end if pos then table.insert(ranks,pos,rank) else table.insert(ranks,rank) end end
function Ranking._set_rank_power() if game then return end for power,rank in pairs(ranks) do rank.power = power end end
function Ranking._update_rank(rank) if game then return end ranks[rank.power] = rank end
function Ranking._update_group(group) if game then return end groups[group.index] = group end
--[[
How to use groups:
name the name that you can use to refence it.
disallow if present then all ranks in this group will have this added to their disallow.
allow if present then all ranks in this group will have this added to their allow.
highest is asigned by the script to show the highest rank in this group.
lowest is asigned by the script to show the lowest rank in this group.
How to add ranks:
Name is what will be used in the scripts and is often the best choice for display in text.
short_hand is what can be used when short on space but the rank still need to be displayed.
tag is the tag the player will gain when moved to the rank, it can be nil.
time is used for auto-rank feature where you are moved to the rank after a certain play time in minutes.
colour is the RGB value that can be used to emphasise GUI elements based on rank.
power is asigned by the script based on their index in ranks, you can insert new ranks between current ones, lower is better
group is asigned by the script to show the group this rank is in
disallow is a list containing input actions that the user can not perform.
allow is a list of custom commands and effects that that rank can use, all defined in the sctips.
For allow, add the allow as the key and the value as true
Example: test for 'server-interface' => allow['server-interface'] = true
For disallow, add to the list the end part of the input action
Example: defines.input_action.drop_item -> 'drop_item'
http://lua-api.factorio.com/latest/defines.html#defines.input_action
--]]
-- If you wish to add more groups please use addons/playerRanks.lua
-- If you wish to add to these rank groups use addons/playerRanks.lua
-- Ranks will inherite from each other ie higher ranks can do everything lower ranks can
-- But groups do not inherite from each other
-- DO NOT REMOVE ANY OF THESE GROUPS
local root = Ranking._group:create{
name='Root',
allow={
['interface'] = true
},
disallow={}
}
local admin = Ranking._group:create{
name='Admin',
allow={},
disallow={
'set_allow_commands',
'edit_permission_group',
'delete_permission_group',
'add_permission_group'
}
}
local user = Ranking._group:create{
name='User',
allow={},
disallow={
'set_allow_commands',
'edit_permission_group',
'delete_permission_group',
'add_permission_group'
}
}
local jail = Ranking._group:create{
name='Jail',
allow={},
disallow={
'set_allow_commands',
'edit_permission_group',
'delete_permission_group',
'add_permission_group',
'open_character_gui',
'begin_mining',
'start_walking',
'player_leave_game',
'open_blueprint_library_gui',
'build_item',
'use_item',
'select_item',
'rotate_entity',
'open_train_gui',
'open_train_station_gui',
'open_gui',
'open_item',
'deconstruct',
'build_rail',
'cancel_research',
'start_research',
'set_train_stopped',
'select_gun',
'open_technology_gui',
'open_trains_gui',
'edit_custom_tag',
'craft',
'setup_assembling_machine',
}
}
-- If you wish to add more ranks please use addons/playerRanks.lua
-- If you wish to add to these rank use addons/playerRanks.lua
root:add_rank{
name='Root',
short_hand='Root',
tag='[Root]',
colour=defines.color.white,
is_root=true,
is_admin=true,
is_spectator=true,
base_afk_time=false
}
admin:add_rank{
name='Admin',
short_hand='Admin',
tag='[Admin]',
colour={r=233,g=63,b=233},
is_admin=true,
is_spectator=true,
base_afk_time=false
}
user:add_rank{
name='Member',
short_hand='Mem',
tag='[Member]',
colour={r=24,g=172,b=188},
disallow={
'set_auto_launch_rocket',
'change_programmable_speaker_alert_parameters',
'drop_item'
},
base_afk_time=60
}
user:add_rank{
name='Guest',
short_hand='',
tag='',
colour={r=255,g=159,b=27},
is_default=true,
disallow={
'build_terrain',
'remove_cables',
'launch_rocket',
'reset_assembling_machine',
'cancel_research'
},
base_afk_time=10
}
jail:add_rank{
name='Jail',
short_hand='Jail',
tag='[Jail]',
colour={r=50,g=50,b=50},
disallow={},
base_afk_time=false
}
function Ranking._auto_edit_ranks()
for power,rank in pairs(ranks) do
if ranks[power-1] then
rank:edit('disallow',false,ranks[power-1].disallow)
end
end
for power = #ranks, 1, -1 do
local rank = ranks[power]
rank:edit('disallow',false,rank.group.disallow)
if ranks[power+1] then
rank:edit('allow',false,ranks[power+1].allow)
end
end
end
-- used to force rank to be read-only
function Ranking._groups(name)
if name then
if name then
local _return = {}
for power,group in pairs(groups) do
_return[group.name] = group
end
return _return
end
end
return groups
end
function Ranking._ranks(name)
if name then
local _return = {}
for power,rank in pairs(ranks) do
_return[rank.name] = rank
end
return _return
end
return ranks
end
-- used to save lag by doing some calculation at the start
function Ranking._meta()
local meta = {time_ranks={}}
for power,rank in pairs(ranks) do
meta.rank_count = power
if rank.is_default then
meta.default = rank.name
end
if rank.is_root then
meta.root = rank.name
end
if rank.time then
table.insert(meta.time_ranks,rank.name)
if not meta.time_highest or power < meta.time_highest then meta.time_highest = power end
if not meta.time_lowest or rank.time < meta.time_lowest then meta.time_lowest = rank.time end
end
end
return meta
end

View File

@@ -0,0 +1,124 @@
--[[
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-----------------------------------------------------------
--[[
How to use groups:
name The name that you can use to reference it.
disallow If present then all ranks in this group will have this added to their disallow.
allow If present then all ranks in this group will have this added to their allow.
highest Assigned by the script to show the highest rank in this group.
lowest Assigned by the script to show the lowest rank in this group.
How to add ranks:
Name What will be used in the scripts and is often the best choice for display in text.
short_hand What can be used when short on space but the rank still need to be displayed.
tag The tag the player will gain when moved to the rank, it can be nil.
time Used for auto-rank feature where you are moved to the rank after a certain play time in minutes.
colour The RGB value that can be used to emphasise GUI elements based on rank.
power Assigned by the script based on their index in ranks, you can insert new ranks between current ones.
group Assigned by the script to show the group this rank is in.
disallow A list containing input actions that the user can not perform.
allow A list of custom commands and effects that that rank can use, all defined in the scripts.
For allow, add the allow as the key and the value as true
Example: test for 'server-interface' => allow['server-interface'] = true
For disallow, add to the list the end part of the input action
Example: defines.input_action.drop_item -> 'drop_item'
http://lua-api.factorio.com/latest/defines.html#defines.input_action
--]]
-- See ExpCore/ranks.lua for examples - you add your own and edit pre-made ones here.
local groups = Ranking._groups(true)
groups['Root']:edit('allow',false,{
['testing']=true
})
groups['Root']:add_rank{
name='Owner',
short_hand='Owner',
tag='[Owner]',
time=nil,
colour={r=170,g=0,b=0},
is_admin = true,
is_spectator=true,
base_afk_time=false
}
groups['Root']:add_rank{
name='Community Manager',
short_hand='Com Mngr',
tag='[Com Mngr]',
colour={r=150,g=68,b=161},
is_admin = true,
is_spectator=true,
base_afk_time=false
}
groups['Root']:add_rank{
name='Developer',
short_hand='Dev',
tag='[Dev]',
colour={r=179,g=125,b=46},
is_admin = true,
is_spectator=true,
base_afk_time=false
}
groups['Admin']:add_rank{
name='Mod',
short_hand='Mod',
tag='[Mod]',
colour={r=0,g=170,b=0},
disallow={
'server_command'
},
is_admin = true,
is_spectator=true,
base_afk_time=false
}
groups['User']:add_rank{
name='Donator',
short_hand='P2W',
tag='[P2W]',
colour={r=233,g=63,b=233},
power=0,
is_spectator=true,
base_afk_time=120
}
groups['User']:add_rank{
name='Veteran',
short_hand='Vet',
tag='[Veteran]',
time=600,
colour={r=140,g=120,b=200},
power=1,
base_afk_time=60
}
groups['User']:add_rank{
name='Regular',
short_hand='Reg',
tag='[Regular]',
time=180,
colour={r=24,g=172,b=188},
power=3,
base_afk_time=30
}
local ranks = Ranking._ranks(true)
ranks['Root']:edit('test',true,'testing')
Ranking._base_preset{
['badgamernl']='Owner',
['arty714']='Community Manager',
['cooldude2606']='Developer',
['mark9064']='Admin'
}

View File

@@ -0,0 +1,392 @@
--[[
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 Ranking = {}
defines.events.rank_change = script.generate_event_name()
Ranking._rank = {}
Ranking._group = {}
-- this is just for debuging when setting you rank powers
function Ranking.output_ranks(player)
local player = Game.get_player(player) or game.player or nil
if not player then return end
for power,rank in pairs(Ranking._ranks()) do
local output = power..') '..rank.name
output=output..' '..rank.tag
local admin = 'No'; if rank.is_root then admin = 'Root' elseif rank.is_admin then admin = 'Yes' end
output=output..' Admin: '..admin
output=output..' Group: '..rank.group.name
output=output..' AFK: '..tostring(rank.base_afk_time)
player_return(output,rank.colour,player)
end
end
-- this function is to avoid errors - see /ranks.lua
function Ranking._ranks(names)
return {}
end
-- this function is to avoid errors - see /ranks.lua
function Ranking._groups(names)
return {}
end
-- this function is to avoid errors - see /ranks.lua
function Ranking._meta()
return {}
end
-- this function is to avoid errors - see addons/playerRanks.lua
function Ranking._base_preset(table)
Ranking._presets().current = table
end
-- this returns a global list
function Ranking._presets()
if not global.exp_core then global.exp_core = {} end
if not global.exp_core.ranking then global.exp_core.ranking = {meta=Ranking._meta(),old={},current={},last_jail=nil} end
return global.exp_core.ranking
end
--- Returns a rank object given a player or rank name
-- @usage Ranking.get_rank(game.player)
-- Ranking.get_rank('admin')
-- @param mixed player|player index|player name|rank name|rank|'server'|'root' what rank to get
-- @treturn table the rank that is linked to mixed
function Ranking.get_rank(mixed)
if not mixed then return false end
local ranks = Ranking._ranks(true)
local _return = false
if is_type(mixed,'table') then
if mixed.index then
_return = game.players[mixed.index] and ranks[mixed.permission_group.name] or nil
else
_return = mixed.group and mixed or nil
end
else
_return = game.players[mixed] and ranks[game.players[mixed].permission_group.name]
or table.autokey(ranks,mixed) and table.autokey(ranks,mixed)
or string.contains(mixed,'server') and Ranking.get_rank(Ranking._presets().meta.root)
or string.contains(mixed,'root') and Ranking.get_rank(Ranking._presets().meta.root)
or nil
end
return _return
end
--- Returns the group object used to sort ranks given group name or see Ranking.get_rank
-- @usage Ranking.get_group(game.player)
-- Ranking.get_group('root')
-- @param mixed player|player index|player name|rank name|rank|'server'|'root'|group name|group what group to get
-- @treturn table the group that is linked to mixed
function Ranking.get_group(mixed)
if not mixed then return false end
local groups = Ranking._groups(true)
local rank = Ranking.get_rank(mixed)
return rank and rank.group
or is_type(mixed,'table') and mixed.ranks and mixed
or is_type(mixed,'string') and table.autokey(groups,mixed) and table.autokey(groups,mixed)
or false
end
--- Prints to all rank of greater/lower power of the rank given
-- @usage Ranking.print('admin','We got a grifer')
-- @param rank_base the rank that acts as the cut off point (rank is always included)
-- @param rtn what do you want to return to the players
-- @tparam defines.color colour the colour that will be used to print
-- @tparam bolean below if true rank below base are printed to
function Ranking.print(rank_base,rtn,colour,below)
local colour = colour or defines.color.white
local rank_base = Ranking.get_rank(rank_base)
local ranks = Ranking._ranks()
if below then
for power,rank in pairs(ranks) do
if rank_base.power <= power then rank:print(rtn,colour,true) end
end
else
for power,rank in pairs(ranks) do
if rank_base.power >= power then rank:print(rtn,colour) end
end
end
end
--- Gives a user a rank
-- @usage Ranking.give_rank(1,'admin')
-- @param player the player to give the rank to
-- @param rank the rank to give to the player
-- @param[opt='server'] by_player the player who is giving the rank
-- @param[opt=game.tick] tick the tick that the rank is being given on
function Ranking.give_rank(player,rank,by_player,tick)
local print_colour = defines.textcolor.info
local tick = tick or game.tick
local by_player_name = Game.get_player(by_player) and Game.get_player(by_player).name or game.player and game.player.name or is_type(by_player,'string') and by_player or 'server'
local rank = Ranking.get_rank(rank) or Ranking.get_rank(Ranking._presets().meta.default)
local player = Game.get_player(player) or error('No Player To Give Rank')
local old_rank = Ranking.get_rank(player) or Ranking.get_rank(Ranking._presets().meta.default)
local message = 'ranking.rank-down'
-- messaging
if old_rank.name == rank.name then return end
if rank.power < old_rank.power then message = 'ranking.rank-up' player.play_sound{path='utility/achievement_unlocked'}
else player.play_sound{path='utility/game_lost'} end
if player.online_time > 60 or by_player_name ~= 'server' then game.print({message,player.name,rank.name,by_player_name},print_colour) end
if rank.group.name ~= 'User' then player_return({'ranking.rank-given',rank.name},print_colour,player) end
if player.tag ~= old_rank.tag then player_return({'ranking.tag-reset'},print_colour,player) end
-- rank change
player.permission_group = game.permissions.get_group(rank.name)
player.tag = rank.tag
if old_rank.group.name ~= 'Jail' then Ranking._presets().old[player.index] = old_rank.name end
player.admin = rank.is_admin or false
player.spectator = rank.is_spectator or false
if defines.events.rank_change then
script.raise_event(defines.events.rank_change,{
name=defines.events.rank_change,
tick=tick,
player_index=player.index,
by_player_name=by_player_name,
new_rank=rank,
old_rank=old_rank
})
end
if rank.group.name == 'Jail' and Ranking._presets().last_jail ~= player.name then
Sync.emit_embeded{
title='Player Jail',
color=Color.to_hex(defines.textcolor.med),
description='There was a player jailed.',
['Player:']=player.name,
['By:']='<<inline>>'..by_player_name,
['Reason:']='No Reason'
}
end
game.write_file('ranking-change.json',
table.json({
tick=tick,
play_time=player.online_time,
player_name=player.name,
by_player_name=by_player_name,
new_rank=rank.name,
old_rank=old_rank.name,
power_increase=(old_rank.power-rank.power)
})..'\n'
, true, 0)
end
--- Revert the last change to a players rank
-- @usage Ranking.revert(1)
-- @param player the player to revert the rank of
-- @param[opt=nil] by_player the player who is doing the revert
function Ranking.revert(player,by_player)
local player = Game.get_player(player)
Ranking.give_rank(player,Ranking._presets().old[player.index],by_player)
end
--- Given the player has a rank in the preset table it is given
-- @usage Ranking.find_preset(1)
-- @param player the player to test for an auto rank
-- @tparam[opt=nil] number tick the tick it happens on
function Ranking.find_preset(player,tick)
local presets = Ranking._presets().current
local meta_data = Ranking._presets().meta
local default = Ranking.get_rank(meta_data.default)
local player = Game.get_player(player)
local current_rank = Ranking.get_rank(player) or {power=-1,group={name='not jail'}}
local ranks = {default}
if current_rank.group.name == 'Jail' then return end
if presets[string.lower(player.name)] then
local rank = Ranking.get_rank(presets[string.lower(player.name)])
table.insert(ranks,rank)
end
if current_rank.power > meta_data.time_highest and tick_to_min(player.online_time) > meta_data.time_lowest then
for _,rank_name in pairs(meta_data.time_ranks) do
local rank = Ranking.get_rank(rank_name)
if tick_to_min(player.online_time) > rank.time then
table.insert(ranks,rank)
end
end
end
local _rank = current_rank
for _,rank in pairs(ranks) do
if rank.power < _rank.power or _rank.power == -1 then _rank = rank end
end
if _rank then
if _rank.name == default.name then
player.tag = _rank.tag
player.permission_group = game.permissions.get_group(_rank.name)
else
Ranking.give_rank(player,_rank,nil,tick)
end
end
end
-- this is the base rank object, do not store in global
--- Is this rank allowed to open this gui or use this command etc.
-- @usage rank:allowed('server-interface')
-- @tparam teh action to test for
-- @treturn bolean is it allowed
function Ranking._rank:allowed(action)
return self.allow[action] or self.is_root or false
end
--- Get all the players in this rank
-- @usage rank:get_players()
-- @tparam bolean online get only online players
-- @treturn table a table of all players in this rank
function Ranking._rank:get_players(online)
local players = game.permissions.get_group(self.name).players
local _return = {}
if online then
for _,player in pairs(players) do
if player.connected then table.insert(_return,player) end
end
else
_return = players
end
return _return
end
--- Print a message to all players of this rank
-- @usage rank:print('foo')
-- @param rtn any value you want to return
-- @tparam define.color colour the colour that will be used to print
-- @tparam boolean show_default weather to use the default rank name for the print
function Ranking._rank:print(rtn,colour,show_default)
local colour = colour or defines.color.white
local meta_data = Ranking._presets().meta
local default = Ranking.get_rank(meta_data.default)
if not Server or not Server._thread then
for _,player in pairs(self:get_players(true)) do
if self.name == default.name or show_default then
player_return({'ranking.all-rank-print',rtn},colour,player)
else
player_return({'ranking.rank-print',self.name,rtn},colour,player)
end
end
else
-- using threads to make less lag
Server.new_thread{
data={rank=self,rtn=rtn,default=default.name,all=show_default}
}:on_event('resolve',function(thread)
return thread.data.rank:get_players(true)
end):on_event('success',function(thread,players)
for _,player in pairs(players) do
if thread.data.rank.name == thread.data.default or thread.data.all then
player_return({'ranking.all-rank-print',thread.data.rtn},colour,player)
else
player_return({'ranking.rank-print',thread.data.rank.name,thread.data.rtn},colour,player)
end
end
end):queue()
end
end
-- this is used to edit a group once made key is what is being edited and set_value makes it over ride the current value
-- see Addons/playerRanks for examples
function Ranking._rank:edit(key,set_value,value)
if game then return end
verbose('Edited Rank: '..self.name..'/'..key)
if set_value then self[key] = value return end
if key == 'disallow' then
self.disallow = table.merge(self.disallow,value,true)
elseif key == 'allow' then
self.allow = table.merge(self.allow,value)
end
Ranking._update_rank(self)
end
-- this is the base group object, do not store in global, these cant be used in game
-- this makes a new group
-- {name='root',allow={},disallow={}}
function Ranking._group:create(obj)
if game then return end
if not is_type(obj.name,'string') then return end
verbose('Created Group: '..obj.name)
setmetatable(obj,{__index=Ranking._group})
self.index = #Ranking._groups(names)+1
obj.ranks = {}
obj.allow = obj.allow or {}
obj.disallow = obj.disallow or {}
Ranking._add_group(obj)
return obj
end
-- this makes a new rank in side this group
-- {name='Root',short_hand='Root',tag='[Root]',time=nil,colour=defines.colors.white,allow={},disallow={}}
-- if the rank is given power then it is given that place realative to the highest rank in that group,if no power then it is added to the end
function Ranking._group:add_rank(obj)
if game then return end
if not is_type(obj.name,'string') or
not is_type(obj.short_hand,'string') or
not is_type(obj.tag,'string') or
not is_type(obj.colour,'table') then return end
verbose('Created Rank: '..obj.name)
setmetatable(obj,{__index=Ranking._rank})
obj.group = self
obj.allow = obj.allow or {}
obj.disallow = obj.disallow or {}
obj.power = obj.power and self.highest and self.highest.power+obj.power or obj.power or self.lowest and self.lowest.power+1 or nil
setmetatable(obj.allow,{__index=self.allow})
setmetatable(obj.disallow,{__index=self.disallow})
Ranking._add_rank(obj,obj.power)
Ranking._set_rank_power()
table.insert(self.ranks,obj)
if not self.highest or obj.power < self.highest.power then self.highest = obj end
if not self.lowest or obj.power > self.lowest.power then self.lowest = obj end
end
-- this is used to edit a group once made key is what is being edited and set_value makes it over ride the current value
-- see Addons/playerRanks for examples
function Ranking._group:edit(key,set_value,value)
if game then return end
verbose('Edited Group: '..self.name..'/'..key)
if set_value then self[key] = value return end
if key == 'disallow' then
self.disallow = table.merge(self.disallow,value,true)
elseif key == 'allow' then
self.allow = table.merge(self.allow,value)
end
Ranking._update_group(self)
end
Event.register(defines.events.on_player_joined_game,function(event)
Ranking.find_preset(event.player_index)
end)
Event.register(-1,function(event)
for power,rank in pairs(Ranking._ranks()) do
local perm = game.permissions.create_group(rank.name)
for _,toRemove in pairs(rank.disallow) do
perm.set_allows_action(defines.input_action[toRemove],false)
end
end
end)
Event.register(defines.events.on_tick,function(event)
if (((event.tick+10)/(3600*game.speed))+(15/2))% 15 == 0 then
-- this is the system to auto rank players
if not Server or not Server._thread then
for _,player in pairs(game.connected_players) do
Ranking.find_preset(player,tick)
end
else
Server.new_thread{
data={players=game.connected_players}
}:on_event('tick',function(thread)
if #thread.data.players == 0 then thread:close() return end
local player = table.remove(thread.data.players,1)
Ranking.find_preset(player,tick)
end):open()
end
end
end)
Ranking.on_init=function(self)
require(module_path.."/base_ranks")
require(module_path.."/config_ranks")
end
return Ranking

View File

@@ -0,0 +1,428 @@
--[[
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-----------------------------------------------------------
-- 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()
-- @treturn string the new uuid
function Server.new_uuid()
local uuid = tostring(Server._uuid()())
uuid = string.to_hex('uuid'..uuid)
return 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
--- 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
-- 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
-- @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
function Server.get_thread(mixed)
local threads = Server._threads()
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]
else return false end
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
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)
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
-- @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
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)
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)
if not success then next_thread:error(err) end
end
end)
end
--- Checks the timeout on all active timeout threads
-- @usage Server.check_timeouts()
function Server.check_timeouts()
table.each(Server._threads().timeout,function(uuid)
local next_thread = Server.get_thread(uuid)
if next_thread and next_thread:valid() then
next_thread:check_timeout()
end
end)
end
-- for use in debuging
function Server._thread_handler_debuger(player,event,state)
local player = Game.get_player(player)
local print_to = Server._threads().print_to
print_to[player.index] = print_to[player.index] or {}
print_to[player.index][event] = state
end
--- Calles all threads on a certain game event (used with script.on_event)
-- @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)
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)
local event_id = event.name
local threads = Server._threads().events[event_id]
if not threads then return end
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
end
end
end)
end
--[[ cant be used V
--- Adds a event handler to tell threads about events
-- @usage Server.add_thread_handler(defines.event)
-- @tparam number event the event to run the thread handler on
-- @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()
if not threads.events[event] then
threads.events[event] = {}
Event.register(event,Server._thread_handler)
return true
end
return false
end
]]
--- Given a string or function it will run that function and return any values
-- @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)
-- @param[opt] ... any args you want to pass to the function
function Server.interface(callback,use_thread,...)
if use_thread then
if use_thread == true then use_thread = Server.new_thread{data={callback,...}} end
use_thread:on_event('resolve',function(thread)
if is_type(thread.data[1],'function') then
local success, err = pcall(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))
if not success then error(err) end
return err
end
end)
use_thread:open()
Server.queue_thread(use_thread)
else
if is_type(callback,'function') then
local success, err = pcall(callback,...)
return success, err
else
local success, err = pcall(loadstring(callback),...)
return success, err
end
return false
end
end
-- thread allows you to run fuinction async to the main game
--- 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
function Server._thread:create(obj)
local obj = obj or {}
setmetatable(obj,{__index=Server._thread})
obj.uuid = Server.new_uuid()
return obj
end
-- see Server.queue_thread - this just opens it first
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
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
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
is_type(self._timeout) or is_type(self._timeout,'function') and
is_type(self._tick) or is_type(self._tick,'function') and
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
return true
end
return false
end
--- Opens the thread by storing it in a place the server object can find it
-- @usage thread:open() -- return true
-- @treturn bolean if the thread was opened
function Server._thread:open()
if not self:valid(true) or self.opened then return false end
local threads = Server._threads()
local uuid = self.uuid
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
if is_type(self._events,'table') then
table.each(self._events,function(callback,event,threads,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)
end
return true
end
--- Inverse of thread:open() - it removes the thread and calles on_close
-- @usage thread:close() -- return true
-- @treturn bolean if the thread had a on_close function
function Server._thread:close()
local threads = Server._threads()
local uuid = self.uuid
local _return = false
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
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
-- cant be used V
--if #threads.events[event] == 0 then Event.remove(event,Server.game_event) threads.events[event] = nil end
end
end)
end
self.opened=nil
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
end
return _return
end
--- Trigger the on_resolve function and closes the thread - error and success called based on result of pcall (useful for async)
-- @usage thread:resolve(x,y,z) -- return true
-- @param[opt] ... any arguments you want to pass to the resolve function
-- @treturn bolean true if the thread called on_success or on_error
function Server._thread:resolve(...)
local _return = false
if is_type(self._resolve,'function') then
local success, err = pcall(self._resolve,self,...)
if success then
if is_type(self._success,'function') then
Server.interface(function(thread,err)
local success,err = pcall(thread._success,thread,err)
if not success then thread:error(err) end
end,true,self,err)
_return = true
end
else
_return = self:error(err)
end
end
self:close()
return _return
end
--- Checks the timeout on a thread - if timedout then it calles on_timeout and closes
-- @usage thread:check_timeout() -- return true
-- @treturn bolean if the thread timedout
function Server._thread:check_timeout()
local _return = false
if not self:valid() then return false end
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)
end
_return = true
self:close()
end
return _return
end
--- Rasies an error on this thread
-- @usage thread:error(err) -- return true
-- @param err the err to be rasied
-- @treturn bolean did the thread handdle the error
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
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
function Server._thread:on_event(event,callback)
local events = {'close','timeout','tick','resolve','success','error'}
local value = table.find(events,function(v,k,find) return v == string.lower(find) end,event)
if value and is_type(callback,'function') then
self['_'..value] = callback
elseif is_type(event,'number') and is_type(callback,'function') then
if not self._events then self._events = {} end
self._events[event] = callback
end
return self
end
Event.register(defines.events.on_tick,function(event)
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 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
end)
Server.on_init=function(self)
Event.register(defines.event,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
end
return Server
--[[
Thread Example:
local thread = Server.new_thread{name='tree-decon',data={}}
-- user thread:on_event('tick') rather than thread:on_event(defines.events.on_tick) as it makes less lag
thread: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)
thread: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)
thread: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)
thread:open()
local thread = Server.new_thread{name='print-place',data={}}
thread:on_event(defines.events.on_built_entity,function(self,event)
game.print('Events')
end)
thread:open()
all on_event functions can be chained from the thread creation rather than use varibles
]]

View File

@@ -0,0 +1,364 @@
--[[
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-----------------------------------------------------------
-- this file is used to allow easy syncing with out side programes
local Sync = {}
local Sync_gui_functions = {}
local Sync_updates = {}
--- Used as a faster way to get to the ranking function, overrides previous
-- @usage Sync.set_ranks{name=rank_name}
function Sync.set_ranks(...)
if Ranking then Ranking._base_preset(...) else error('Ranking module not installed') end
end
--- Used to standidise the tick format for any sync info
-- @usage Sync.tick_format(60) -- return {60,'1.00M'}
function Sync.tick_format(tick)
return {tick,tick_to_display_format(tick)}
end
--- Prints to chat as if it were a player
-- @usage Sync.print('Test','Cooldude2606')
-- @param player_message the message to be printed in chat
-- @param player_name the name of the player sending the message
-- @param[opt] player_tag the tag apllied to the player's name
-- @param[opt] player_colour the colour of the message
-- @param[opt] prefix add a prefix before the chat eg [IRC]
function Sync.print(player_message,player_name,player_tag,player_colour,prefix)
if not player_message then return 'No Message Found' end
local player = game.player or game.players[player_name]
local tag = player_tag and player_tag ~= '' and ' '..player_tag or ''
local colour = player_colour and player_colour ~= '' and player_colour or '#FFFFFF'
local prefix = prefix and prefix..' ' or ''
if player then
tag = ' '..player.tag
colour = player.chat_color
player_name = player.name
else
if colour:find('#') then
colour = Color.from_hex(colour)
else
colour = defines.color[player_colour]
end
end
game.print(prefix..player_name..tag..': '..player_message,colour)
end
--- Logs an embed to the json.data we use a js script to add things we cant here
-- @usage Sync.emit_embeded{title='BAN',color='0x0',description='A player was banned' ... }
-- @tparam table args a table which contains everything that the embeded will use
-- @field title the tile of the embed
-- @field color the color given in hex you can use Color.to_hex{r=0,g=0,b=0}
-- @field description the description of the embed
-- @field server_detail sting to add onto the pre-set server detail
-- @field fieldone the filed to add to the embed (key is name) (value is text) (start value with <<inline>> to make inline)
-- @field fieldtwo the filed to add to the embed (key is name) (value is text) (start value with <<inline>> to make inline)
function Sync.emit_embeded(args)
if not is_type(args,'table') then return end
local title = is_type(args.title,'string') and args.title or ''
local color = is_type(args.color,'string') and args.color:find("0x") and args.color or '0x0'
local description = is_type(args.description,'string') and args.description or ''
local server_detail = is_type(args.server_detail,'string') and args.server_detail or ''
local mods_online = 'Mods Online: '..Sync.info().players.admins_online
local done, fields = {title=true,color=true,description=true,server_detail=true}, {{
name='Server Details',
value='Server Name: {{ serverName }} Online Players: '..#game.connected_players..' '..mods_online..' Server Time: '..tick_to_display_format(game.tick)..' '..server_detail
}}
for key, value in pairs(args) do
if not done[key] then
done[key] = true
local f = {name=key,value='',inline=false}
local value, inline = value:gsub("<<inline>>",'',1)
f.value = value
if inline > 0 then f.inline = true end
table.insert(fields,f)
end
end
local log_data = {
title=title,
description=description,
color=color,
fields=fields
}
game.write_file('embeded.json',table.json(log_data)..'\n',true,0)
end
-- set up error handle
error.addHandler('Discord Emit',function(err)
local color = _G.Color and Color.to_hex(defines.textcolor.bg) or '0x0'
Sync.emit_embeded{title='SCRIPT ERROR',color=color,description='There was an error in the script @Developers ',Error=err}
end)
--- used to get the number of admins currently online
-- @usage Sync.count_admins()
-- @treturn int the number of admins online
function Sync.count_admins()
if not game then return 0 end
local _count = 0
for _,player in pairs(game.connected_players) do
if player.admin then _count=_count+1 end
end
return _count
end
--- used to get the number of afk players defined by 2 min by default
-- @usage Sync.count_afk()
-- @tparam[opt=7200] int time in ticks that a player is called afk
-- @treturn int the number of afk players
function Sync.count_afk(time)
if not game then return 0 end
local time = time or 7200
local _count = 0
for _,player in pairs(game.connected_players) do
if player.afk_time > time then _count=_count+1 end
end
return _count
end
--- used to get the number of players in each rank and currently online
-- @usage Sync.count_ranks()
-- @treturn table contains the ranks and the players in that rank
function Sync.count_ranks()
if not game then return {'Offline'} end
if not Ranking then return {'Ranking module not installed'} end
local _ranks = {}
for power,rank in pairs(Ranking._ranks()) do
local players = rank:get_players()
for k,player in pairs(players) do players[k] = player.name end
local online = rank:get_players(true)
for k,player in pairs(online) do online[k] = player.name end
_ranks[rank.name] = {players=players,online=online,n_players=#players,n_online=#online}
end
return _ranks
end
--- used to get the number of players either online or all
-- @usage Sync.count_players()
-- @tparam bolean online if true only get online players
-- @treturn table contains player names
function Sync.count_players(online)
if not game then return {'Offline'} end
local _players = {}
local players = {}
if online then _players = game.connected_players else _players = game.players end
for k,player in pairs(_players) do table.insert(players,player.name) end
return players
end
--- used to get the number of players resulting in there play times
-- @usage Sync.count_player_times()
-- @treturn table contains players and each player is given a tick amount and a formated string
function Sync.count_player_times()
if not game then return {'Offline'} end
local _players = {}
for index,player in pairs(game.players) do
_players[player.name] = Sync.tick_format(player.online_time)
end
return _players
end
--- used to return the global list and set values in it
-- @usage Sync.info{server_name='Factorio Server 2'}
-- @tparam[opt=nil] table set keys to be replaced in the server info
-- @return either returns success when setting or the info when not setting
function Sync.info(set)
if not global.exp_core then global.exp_core = {} end
if not global.exp_core.sync then global.exp_core.sync = {
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=Sync.tick_format(0),
last_update=Sync.tick_format(0),
time_period=Sync.tick_format(18000),
players={
online=Sync.count_players(true),
n_online=#game.connected_players,
all=Sync.count_players(),
n_all=#game.players,
admins_online=Sync.count_admins(),
afk_players=Sync.count_afk(),
times=Sync.count_player_times()
},
ranks=Sync.count_ranks(),
rockets=game.forces['player'].get_item_launched('satellite'),
mods={'base'}
} end
if not set then return global.exp_core.sync
else
if not is_type(set,'table') then return false end
for key,value in pairs(set) do
global.exp_core.sync[key] = value
end
return true
end
end
--- used to return the global time and set its value
-- @usage Sync.time('Sun Apr 1 18:44:30 UTC 2018')
-- @tparam[opt=nil] string set the date time to be set
-- @return either true false if setting or the date time and tick off set
function Sync.time(set)
local info = Sync.info()
if not set then return info.time..' (+'..(game.tick-info.time_set[1])..' Ticks)'
else
if not is_type(set,'string') then return false end
info.time = set
info.time_set[1] = game.tick
info.time_set[2] = tick_to_display_format(game.tick)
return true
end
end
--- called to update values inside of the info
-- @usage Sync.update()
-- @return all of the new info
function Sync.update()
local info = Sync.info()
info.time_period[2] = tick_to_display_format(info.time_period[1])
info.last_update[1] = game.tick
info.last_update[2] = tick_to_display_format(game.tick)
info.players={
online=Sync.count_players(true),
n_online=#game.connected_players,
all=Sync.count_players(),
n_all=#game.players,
admins_online=Sync.count_admins(),
afk_players=Sync.count_afk(),
times=Sync.count_player_times()
}
info.ranks = Sync.count_ranks()
info.rockets = game.forces['player'].get_item_launched('satellite')
for key,callback in pairs(Sync_updates) do info[key] = callback() end
return info
end
--- Adds a callback to be called when the info is updated
-- @usage Sync.add_update('players',function() return #game.players end)
-- @tparam string key the key that the value will be stored in
-- @tparam function callback the function which will return this value
function Sync.add_update(key,callback)
if game then return end
if not is_type(callback,'function') then return end
Sync_updates[key] = callback
end
--- outputs the curent server info into a file
-- @usage Sync.emit_data()
function Sync.emit_data()
local info = Sync.info()
game.write_file('server-info.json',table.json(info),false,0)
end
-- will auto replace the file every 5 min by default
Event.register(defines.events.on_tick,function(event)
local time = Sync.info().time_period[1]
if (event.tick%time)==0 then Sync.update() Sync.emit_data() end
end)
--- Adds a emeltent to the sever info gui
-- @usage Sync.add_to_gui('string') -- return trues
-- @param element see examples before for what can be used, it can also be a return from Gui.inputs.add
-- @treturn bolean based on weather it was successful or not
function Sync.add_to_gui(element,...)
if game then return false end
if is_type(element,'function') then
table.insert(Sync_gui_functions,{'function',element,...})
elseif is_type(element,'table') then
if element.draw then table.insert(Sync_gui_functions,{'gui',element})
else table.insert(Sync_gui_functions,{'table',element}) end
else table.insert(Sync_gui_functions,{'string',element}) end
return true
end
Sync.on_init=function(self)
-- Examples for Sync.add_to_gui
-- adds a basic string to the table
Sync.add_to_gui('Welcome to the Explosive Gaming comunity! This is one of many servers which we host.')
if Ranking then
-- adds a string that can have depentant values
Sync.add_to_gui(function(player,frame)
return 'You have been assigned the rank \''..Ranking.get_rank(player).name..'\''
end)
end
Sync.add_to_gui(function(player,frame)
return 'This server will reset at: '..Sync.info().reset_time
end)
end
-- if readme is included then see addons/guis/readme.lua for more examples
-- used to load the gui infomation when _G.Gui is not yet loaded
-- internal use not recomend to be used
function Sync._load()
local function label_format(label,width)
label.style.width = width
label.style.align = 'center'
label.style.single_line = false
end
Gui.center.add{
name='server-info',
caption='Server Info',
tooltip='Basic info about the current server',
draw=function(self,frame)
frame.caption = ''
local info = Sync.info()
local frame = frame.add{type='flow',direction='vertical'}
local _flow = frame.add{type='flow'}
Gui.bar(_flow,200)
label_format(_flow.add{
type='label',
caption='Welcome To '..info.server_name,
style='caption_label'
},180)
Gui.bar(_flow,200)
label_format(frame.add{
type='label',
caption=info.server_description,style='description_label'
},600)
Gui.bar(frame,600)
local _frame = frame
local frame = frame.add{
type='frame',
direction='vertical',
style='image_frame'
}
frame.style.width = 600
local text_flow = frame.add{type='flow',direction='vertical'}
local button_flow = frame.add{type='table',column_count=3}
for _,element in pairs(table.deepcopy(Sync_gui_functions)) do
local _type = table.remove(element,1)
if _type == 'function' then
local success, err = pcall(table.remove(element,1),frame.player_index,frame,unpack(element))
if not success then error(err) else
if is_type(err,'table') then
if element.draw then element:draw(button_flow).style.width = 195
else label_format(text_flow.add{type='label',caption=err},585) end
else label_format(text_flow.add{type='label',caption=tostring(err)},585) end
end
elseif _type == 'gui' then element[1]:draw(button_flow).style.width = 195
elseif _type == 'string' then label_format(text_flow.add{type='label',caption=tostring(element[1])},585)
elseif _type == 'table' then label_format(text_flow.add{type='label',caption=element[1]},585) end
end
_frame.add{
type='label',
caption='Press Ecs or E to close; this is only visible once!',
style='fake_disabled_label'
}.style.font='default-small'
end}
end
-- opens the server info gui for all new joins except admins
Event.register(defines.events.on_player_joined_game,function(event)
local player = Game.get_player(event)
Gui.center.open(player,'server-info')
end)
return Sync

View File

@@ -0,0 +1,75 @@
{
"name": "ExpGamingCore",
"module": "Collection",
"description": "Explosive Gaming Core Files",
"keywords": ["Library","Lib","ExpGaming","Core"],
"version": "3.4.0",
"location": "url",
"submodules": {
"Commands": {
"name": "Commands",
"module": "commands",
"description": "A better command handler than the base game.",
"keywords": ["Library","Lib","ExpGaming","Core","Commands"],
"version": "3.4.0",
"location": "url",
"dependencies": {
"ExpGamingLib": ">=3.0.0",
"ExpGamingCore/Ranking": ">=3.0.0"
}
},
"Gui": {
"name": "Gui",
"module": "Gui",
"description": "Adds a objective version to custom guis.",
"keywords": ["Library","Lib","ExpGaming","Core","Gui","ExpGui"],
"version": "3.4.0",
"location": "url",
"dependencies": {
"FactorioModGui": ">=1.0.0",
"ExpGamingLib": ">=3.0.0",
"ExpGamingCore/Ranking": ">=3.0.0",
"ExpGamingCore/Server": "?>=3.0.0"
}
},
"Ranking": {
"name": "Ranking",
"module": "Ranking",
"description": "A full ranking system for factorio.",
"keywords": ["Library","Lib","ExpGaming","Core","Ranking","Ranks","Permissions","Roles"],
"version": "3.4.0",
"location": "url",
"dependencies": {
"ExpGamingLib": ">=3.0.0"
}
},
"Server": {
"name": "Server",
"module": "Server",
"description": "Adds a thread system and event listening and a admin bypass (recommend to disable /c and use optional /interface)",
"keywords": ["Library","Lib","ExpGaming","Core","Server","Thread","Interface","Events"],
"version": "3.4.0",
"location": "url",
"dependencies": {
"ExpGamingLib": ">=3.0.0",
"ExpGamingCore/Ranking": "?>=3.0.0",
"ExpGamingCore/Commands": "?>=3.0.0"
}
},
"Sync": {
"name": "Sync",
"module": "Sync",
"description": "Allows syncing with an outside server and info panle.",
"keywords": ["Library","Lib","ExpGaming","Core","Info","Sync","External","Discord"],
"version": "3.4.0",
"location": "url",
"dependencies": {
"ExpGamingLib": ">=3.0.0",
"Ranking": "?>=3.0.0"
}
}
},
"author": "Cooldude2606",
"contact": "Discord: Cooldude2606#5241",
"license": "https://github.com/badgamernl/explosivegaming-main/blob/master/LICENSE"
}

View File

@@ -3,12 +3,12 @@
"module": "ExpLib",
"description": "Adds some common functions used though out all ExpGaming modules",
"keywords": ["ExpGaming","Lib"],
"version": "1.0.0",
"location": "nil",
"main": "control",
"version": "3.4.0",
"location": "url",
"dependencies": {
"StdLib/Game": ">=1.0.0",
"StdLib/Color": ">=1.0.0"
"StdLib.Game": ">=0.8.0",
"StdLib.Color": ">=0.8.0",
"StdLib.Table": ">=0.8.0"
},
"author": "Cooldude2606",
"contact": "Discord: Cooldude2606#5241",

View File

@@ -0,0 +1,6 @@
--- Redirect to factorio mod-gui
-- @module Factorio Mod Gui
-- @alias mod-gui
-- @author Factorio Dev Team
return require("mod-gui")

View File

@@ -0,0 +1,12 @@
{
"name": "FactorioModGui",
"module": "mod_gui",
"description": "A way to standadise the way mods hanndle their guis.",
"keywords": ["Factorio","Gui","Non-Download","Included"],
"version": "1.0.0",
"location": "url",
"dependencies": {},
"author": "Factorio Dev Team",
"contact": "Any other questions please feel free to ask on the modding help forum.",
"license": "C:/Program Files (x86)/Steam/steamapps/common/Factorio/data/licenses.txt"
}

View File

@@ -410,7 +410,7 @@ function table.val_to_str(v)
end
return '"'..string.gsub(v,'"', '\\"' )..'"'
else
return "table" == type( v) and table.to_string(v) or
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)
@@ -450,7 +450,7 @@ function table.tostring(tbl)
return "{"..table.concat(result,",") .."}"
end
--- Simmilar to table.to_string but converts a lua table to a json one
--- Simmilar to table.tostring but converts a lua table to a json one
-- @usage local a = {k1='foo',k2='bar'}
-- talbe.json(a) -- return '{"k1":"foo","k2":"bar"}'
-- @tparam table lua_table the table to convert

View File

@@ -1,10 +1,10 @@
{
"name": "FactorioStdLib",
"module": "StdLib",
"module": "Collection",
"description": "Factorio Standard Library Projects",
"keywords": ["Standard Library","Lib","StdLib"],
"version": "0.8.0",
"location": "nil",
"location": "url",
"submodules": {
"Color": {
"name": "Color",
@@ -12,7 +12,7 @@
"description": "A defines module for retrieving colors by name.",
"keywords": ["Standard Library","Lib","StdLib","Color","Extends"],
"version": "0.8.0",
"location": "color",
"location": "url",
"dependencies": {}
},
"Game": {
@@ -21,7 +21,7 @@
"description": "The game module.",
"keywords": ["Standard Library","Lib","StdLib","Game","Extends"],
"version": "0.8.0",
"location": "game",
"location": "url",
"dependencies": {}
},
"String": {
@@ -30,7 +30,7 @@
"description": "Extends Lua 5.2 string.",
"keywords": ["Standard Library","Lib","StdLib","String","Extends"],
"version": "0.8.0",
"location": "string",
"location": "url",
"dependencies": {}
},
"Table": {
@@ -39,7 +39,7 @@
"description": "Extends Lua 5.2 table.",
"keywords": ["Standard Library","Lib","StdLib","Table","Extends"],
"version": "0.8.0",
"location": "table",
"location": "url",
"dependencies": {}
},
"Time": {
@@ -48,7 +48,7 @@
"description": "A defines module for retrieving the number of ticks in 1 unit of time.",
"keywords": ["Standard Library","Lib","StdLib","Time","Extends"],
"version": "0.8.0",
"location": "time",
"location": "url",
"dependencies": {}
}
},

View File

@@ -1,10 +1,16 @@
--- Used to index the files to be loaded
-- @script index.lua
return {
['ExpLib']='/modules/ExpGamingLib/control',
['Game']='/modules/FactorioStdLib/game',
['Time']='/modules/FactorioStdLib/time',
['Color']='/modules/FactorioStdLib/color',
['table']='/modules/FactorioStdLib/table',
['string']='/modules/FactorioStdLib/string',
['mod_gui']='/modules/FactorioModGui',
['ExpLib']='/modules/ExpGamingLib',
['Game']='/modules/FactorioStdLib/Game',
['Time']='/modules/FactorioStdLib/Time',
['Color']='/modules/FactorioStdLib/Color',
['table']='/modules/FactorioStdLib/Table',
['string']='/modules/FactorioStdLib/String',
['Ranking']='/modules/ExpGamingCore/Ranking',
['commands']='/modules/ExpGamingCore/Commands',
['Gui']='/modules/ExpGamingCore/Gui',
['Server']='/modules/ExpGamingCore/Server',
['Sync']='/modules/ExpGamingCore/Sync',
}