--@name Logan's Starfall Toolkit --@author logan2611 --@server --@include lsft/cl_lsft.txt --@includedir lsft/modules/server --@includedir lsft/modules/shared --@clientmain lsft/cl_lsft.txt -- SPAWN THIS ONE --[[ _ ____ _____ _____ | | / ___|| ___|_ _| | | _____ \___ \| |_ | | | |___ |_____| ___) | _| | | |_____| |____/|_| |_| --]] --[[ TODO: Update checker TODO: On module load, grab default config values. Write changed values prop.createSent(chip():getPos()+Vector(0,0,90),Angle(0,0,0),"Seat_Airboat",true) --]] -- Main Module (Mostly loading modules and stuff) core = {} do local function stats() -- For debugging purposes mostly core:log(log.TEXT, "---------------------------") core:log(log.TEXT, "Server Stats:") core:log(log.INFO, "Max CPU: ", core.colors.text, math.round(core.maxCPU*1000000).."us ("..math.round(core.maxCPU*100/quotaMax()).."%)") core:log(log.INFO, "Max RAM: ", core.colors.text, math.round(core.maxRAM).."kB ("..math.round(core.maxRAM*100/ramMax()).."%)") core:log(log.INFO, "Min Net: ", core.colors.text, core.minNet.." bytes") core:log(log.TEXT, "---------------------------") end local function hud() if core.hud then enableHud(owner(),false) core.hud = false else enableHud(owner(),true) core.hud = true end end local function help(args) local module = args[1] local command = args[2] if module == nil and command == nil then core:log(log.TEXT, "---------------------------") core:log(log.INFO, "To list the commands in a module, type "..core:get_config("core", "command_prefix").."help ") core:log(log.INFO, "List of available modules:") local modules = {} for i, v in pairs(core.modules) do table.insert(modules, core.colors.logo) table.insert(modules, "[L-SFT] ") table.insert(modules, core.colors.info) table.insert(modules, "\""..i.."\" | "..(v.desc or "No description provided.").."\n") end modules[#modules] = modules[#modules]:sub(1, -2) print(unpack(modules)) core:log(log.TEXT, "---------------------------") elseif module ~= nil and command == nil then if not core.modules[module] then core:log(log.ERROR, "Module does not exist!") return end core:log(log.TEXT, "---------------------------") core:log(log.INFO, "List of available commands in module \""..module.."\":") local commands = {} for i, v in pairs(core.modules[module].commands) do table.insert(commands, core.colors.logo) table.insert(commands, "[L-SFT] ") table.insert(commands, core.colors.info) table.insert(commands, "\""..i.."\" | Usage: "..(v.usage or "No usage provided.").."\n") end commands[#commands] = commands[#commands]:sub(1, -2) print(unpack(commands)) core:log(log.TEXT, "---------------------------") elseif module ~= nil and command ~= nil then if not core.modules[module].commands[command] then core:log(log.ERROR, "Command does not exist in module \""..module.."\"!") return end core:log(log.TEXT, "---------------------------") core:log(log.INFO, "Usage: "..(core.modules[module].commands[command].usage or "Command: "..command.." (No usage provided)")) core:log(log.INFO, "Description: "..(core.modules[module].commands[command].desc or "No description provided.")) core:log(log.TEXT, "---------------------------") else core:log(log.ERROR, "Universe is broken.") end end core.modules = { core = { version = 0.1, desc = "Built in module.", commands = { stats = { func = stats, usage = "stats", desc = "Gets performance information about this Starfall chip.", }, hud = { func = hud, usage = "hud", desc = "Toggles the built in Starfall HUD", }, help = { desc = "List modules, list commands in a module or gets information about a specific command.", usage = "help [module] [command]", func = help, }, }, }, } end core.config = {} core.defaultconfig = { core = { command_prefix = "!n", colors = { logo = Color(255,200,50), text = Color(255,255,255), info = Color(50,150,255), warn = Color(255,120,50), error = Color(255,50,50), }, controls = { forward = KEY.W, backward = KEY.S, left = KEY.A, right = KEY.D, up = KEY.SPACE, down = KEY.CTRL, run = KEY.SHIFT, }, }, } core.colors = {} core.maxCPU = 0 core.minNet = net.getBytesLeft() core.maxRAM = 0 log = { ERROR=0, WARNING=1, INFO=2, TEXT=3 } function core:init(config) -- If the streamed config exists and has stuff in it, use it instead of the empty one if config != nil and #config > 0 then core.config = config end core:load_modules() local hud = prop.createComponent(chip():getPos(), Angle(0,0,0), "starfall_hud", "models/bull/dynamicbutton.mdl", true) hud:linkComponent(chip()) hud:setSolid(false) hud:setColor(Color(255,255,255,0)) enableHud(owner(), true) core.hud = true core.colors.logo = core:get_config("core","colors","logo") core.colors.text = core:get_config("core","colors","text") core.colors.info = core:get_config("core","colors","info") core.colors.warn = core:get_config("core","colors","warn") core.colors.error = core:get_config("core","colors","error") core.command_prefix = core:get_config("core","command_prefix") core:log(log.INFO, "Loaded v"..core.modules.core.version.." successfully") net.start("LSFT-Loaded") net.send() return true end function core:get_config(...) local args = {...} local cur = core.config for arg in pairs(args) do for i,v in pairs(cur) do if i == args[arg] then if type(v) == "table" then --cur = cur[i] cur = v continue else return v end end end end local cur = core.defaultconfig for arg in pairs(args) do for i,v in pairs(cur) do if i == args[arg] then if type(v) == "table" then --cur = cur[i] cur = v continue else return v end end end end error("Config value requested, but no current or default entry exists!") end function core:load_modules() dodir("lsft/modules/server") dodir("lsft/modules/shared") hook.add("PlayerSay", "CommandCheck", function(ply, str) if ply == owner() and string.find(str, "^"..core.command_prefix) then local stringin = string.explode(" ", str) local command = string.sub(stringin[1], #core.command_prefix+1) local args = {} for i, v in pairs(stringin) do if i == 1 then continue end table.insert(args, v) end for i, v in pairs(core.modules) do for commandin, commandthing in pairs(v["commands"]) do if command == commandin then commandthing.func({unpack(args)}) return "" end end end --print(core.color_logo, "[L-SFT] ", core.color_error, "Error: \""..command.."\" is not a valid command!") core:log(log.ERROR, "\""..command.."\" is not a valid command!") return "" end end) end function core:log(...) local args = {...} local loglevel = args[1] local message = { unpack(args, 2, #args) } local color = Color(0,0,0) if loglevel == log.ERROR then color = core.colors.error elseif loglevel == log.WARNING then color = core.colors.warn elseif loglevel == log.INFO then color = core.colors.info elseif loglevel == log.TEXT then color = core.colors.text end print(core.colors.logo, "[L-SFT] ", color, unpack(message)) end net.receive("LSFT-Config-Read", function(len, ply) if ply == owner() then -- Colors settings aren't loaded yet, so use dumb printing method with default colors (Don't ever do this >:c) --print(core.defaultconfig.core.color_logo, "[L-SFT] ", core.defaultconfig.core.color_info, "Downloading configuration: 0%") timer.create("ConfigProgress", 0.25, 0, function() print(core.defaultconfig.core.colors.logo, "[L-SFT] ", core.defaultconfig.core.colors.info, "Downloading configuration: ", math.round(net.getStreamProgress() * 100, 2), "%") end) net.readStream(function(data) timer.remove("ConfigProgress") core:init(json.decode(data)) end) else print(core.defaultconfig.core.colors.logo, "[L-SFT] ", core.defaultconfig.core.colors.error, ply:getName().." is trying to give us a config") end end) net.receive("LSFT-Get-Config", function() net.start(net.readString()) local output = {} while true do local temp = net.readTable() if #temp == 0 then break end net.writeTable({core:get_config(unpack(temp))}) -- what the fuck end net.send() end) timer.create("CPUCheck", 1, 0, function() if quotaAverage() > core.maxCPU then core.maxCPU = quotaAverage() end if quotaAverage() > quotaMax() * 0.5 then core:log(log.WARNING, "CPU quota is low! ("..math.round(100-(quotaAverage()*100/quotaMax())).."% remaining)") elseif quotaAverage() > quotaMax() * 0.9 then core:log(log.ERROR, "CPU quota is critically low! ("..math.round(100-(quotaAverage()*100/quotaMax())).."% remaining)") timer.pause("CPUCheck") timer.pause("NetCheck") timer.pause("RAMCheck") timer.simple(10, function() timer.unpause("CPUCheck") timer.unpause("NetCheck") timer.unpause("RAMCheck") end) end end) timer.create("NetCheck", 1, 0, function() if net.getBytesLeft() < core.minNet then core.minNet = net.getBytesLeft() end if net.getBytesLeft() < 3000 then core:log(log.WARNING, "Network bandwidth is low! ("..net.getBytesLeft().." bytes left)") elseif net.getBytesLeft() < 1000 then core:log(log.ERROR, "Network bandwidth is critically low! ("..net.getBytesLeft().." bytes left)") end end) timer.create("RAMCheck", 1, 0, function() if ramUsed() > core.maxRAM then core.maxRAM = ramUsed() end if ramUsed() > ramMax() * 0.5 then core:log(log.WARNING, "RAM usage is high! ("..math.round(ramUsed()*100/ramMax()).."% used)") elseif ramUsed() > ramMax() * 0.9 then core:log(log.ERROR, "RAM usage is critically high! ("..math.round(ramUsed()*100/ramMax()).."% used)") end end)