2021-12-14 20:11:04 -05:00
|
|
|
--@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 = {}
|
|
|
|
|
2021-12-16 02:07:35 -05:00
|
|
|
do
|
|
|
|
local function stats()
|
2022-03-26 01:46:47 -04:00
|
|
|
net.start("LSFT-StatsRequest")
|
|
|
|
net.send()
|
|
|
|
|
|
|
|
local peakClientCPUTime = 0
|
|
|
|
local peakClientCPUPercent = 0
|
|
|
|
|
|
|
|
local peakClientRAM = 0
|
|
|
|
local peakClientRAMPercent = 0
|
|
|
|
|
|
|
|
local minClientNet = 2^31
|
|
|
|
|
|
|
|
local plys = 0
|
|
|
|
|
|
|
|
local function displayStats()
|
2022-03-26 04:34:32 -04:00
|
|
|
core:logConsole(log.TEXT, "---------------------------")
|
|
|
|
core:logConsole(log.TEXT, "Server Stats:")
|
|
|
|
core:logConsole(log.INFO, "Max CPU: ", core.colors.text, math.round(core.maxCPU*1000000).."us ("..math.round(core.maxCPU*100/quotaMax()).."%)")
|
|
|
|
core:logConsole(log.INFO, "Max RAM: ", core.colors.text, math.round(core.maxRAM).."kB ("..math.round(core.maxRAM*100/ramMax()).."%)")
|
|
|
|
core:logConsole(log.INFO, "Min Net: ", core.colors.text, core.minNet.." bytes")
|
|
|
|
core:logConsole(log.TEXT, "")
|
|
|
|
core:logConsole(log.TEXT, "Client Stats:")
|
|
|
|
core:logConsole(log.INFO, "Max CPU: ", core.colors.text, math.round(peakClientCPUTime*1000000).."us")
|
|
|
|
core:logConsole(log.INFO, "Max CPU %: ", core.colors.text, math.round(peakClientCPUPercent*100, 2).."%")
|
|
|
|
core:logConsole(log.INFO, "Max RAM: ", core.colors.text, math.round(peakClientRAM).."kB")
|
|
|
|
core:logConsole(log.INFO, "Max RAM %: ", core.colors.text, math.round(peakClientRAMPercent*100, 2).."%")
|
|
|
|
core:logConsole(log.INFO, "Min Net: ", core.colors.text, minClientNet.." bytes")
|
|
|
|
core:logConsole(log.INFO, "Errored Clients: ", core.colors.text, #chip():getErroredPlayers())
|
|
|
|
core:logConsole(log.TEXT, "---------------------------")
|
|
|
|
|
|
|
|
core:log(log.INFO, "Finished, check your developer console.")
|
2022-03-26 01:46:47 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
timer.create("displaystats", 5, 1, displayStats)
|
|
|
|
|
|
|
|
net.receive("LSFT-StatsResponse", function()
|
|
|
|
plys = plys + 1
|
|
|
|
local clientCPUTime = net.readFloat()
|
|
|
|
local clientCPUPercent = clientCPUTime/net.readFloat()
|
|
|
|
|
|
|
|
local clientRAM = net.readFloat()
|
|
|
|
local clientRAMPercent = clientRAM/net.readFloat()
|
|
|
|
|
|
|
|
local clientNet = net.readFloat()
|
|
|
|
|
|
|
|
-- Comparison
|
|
|
|
if clientCPUTime > peakClientCPUTime then peakClientCPUTime = clientCPUTime end
|
|
|
|
if clientCPUPercent > peakClientCPUPercent then peakClientCPUPercent = clientCPUPercent end
|
|
|
|
|
|
|
|
if clientRAM > peakClientRAM then peakClientRAM = clientRAM end
|
|
|
|
if clientRAMPercent > peakClientRAMPercent then peakClientRAMPercent = clientRAMPercent end
|
|
|
|
|
|
|
|
if clientNet < minClientNet then minClientNet = clientNet end
|
|
|
|
|
|
|
|
-- If we have gotten a response from everyone, fuck the timer
|
|
|
|
-- There is a function that tells us when players are ready to receive stuff, but idk where it is and I'm too lazy to make one
|
|
|
|
if plys == #find.allPlayers() then timer.remove("displaystats") displayStats() end
|
|
|
|
end)
|
|
|
|
|
2022-03-26 04:34:57 -04:00
|
|
|
core:log(log.INFO, "Collecting data, please wait...")
|
2021-12-16 02:07:35 -05:00
|
|
|
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 <module>")
|
|
|
|
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)
|
2022-03-26 04:34:57 -04:00
|
|
|
table.insert(modules, "\""..i.."\" | ")
|
|
|
|
table.insert(modules, core.colors.text)
|
|
|
|
table.insert(modules, (v.desc or "No description provided.").."\n")
|
2021-12-16 02:07:35 -05:00
|
|
|
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)
|
2022-03-26 04:34:57 -04:00
|
|
|
table.insert(commands, "\""..i.."\" | Usage: ")
|
|
|
|
table.insert(commands, core.colors.text)
|
|
|
|
table.insert(commands, (v.usage or "No usage provided.").."\n")
|
2021-12-16 02:07:35 -05:00
|
|
|
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, "---------------------------")
|
2022-03-26 04:34:57 -04:00
|
|
|
core:log(log.INFO, "Usage: ", core.colors.text, (core.modules[module].commands[command].usage or "Command: "..command.." (No usage provided)"))
|
|
|
|
core:log(log.INFO, "Description: ", core.colors.text, (core.modules[module].commands[command].desc or "No description provided."))
|
2021-12-16 02:07:35 -05:00
|
|
|
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",
|
2022-03-26 04:34:57 -04:00
|
|
|
desc = "Toggles the built in Starfall HUD.",
|
2021-12-16 02:07:35 -05:00
|
|
|
},
|
|
|
|
help = {
|
|
|
|
desc = "List modules, list commands in a module or gets information about a specific command.",
|
|
|
|
usage = "help [module] [command]",
|
|
|
|
func = help,
|
|
|
|
},
|
|
|
|
},
|
2021-12-14 20:11:04 -05:00
|
|
|
},
|
2021-12-16 02:07:35 -05:00
|
|
|
}
|
|
|
|
end
|
2021-12-14 20:11:04 -05:00
|
|
|
|
|
|
|
core.config = {}
|
|
|
|
core.defaultconfig = {
|
|
|
|
core = {
|
|
|
|
command_prefix = "!n",
|
2021-12-16 02:07:35 -05:00
|
|
|
colors = {
|
|
|
|
logo = Color(255,200,50),
|
|
|
|
text = Color(255,255,255),
|
2022-03-26 04:34:57 -04:00
|
|
|
info = Color(150,200,255),
|
2021-12-16 02:07:35 -05:00
|
|
|
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,
|
|
|
|
},
|
2021-12-14 20:11:04 -05:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2022-03-26 04:34:57 -04:00
|
|
|
|
2021-12-16 02:07:35 -05:00
|
|
|
core.colors = {}
|
|
|
|
|
|
|
|
core.maxCPU = 0
|
|
|
|
core.minNet = net.getBytesLeft()
|
|
|
|
core.maxRAM = 0
|
|
|
|
|
2022-03-26 04:34:57 -04:00
|
|
|
|
2021-12-14 20:11:04 -05:00
|
|
|
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()
|
|
|
|
|
2021-12-16 02:07:35 -05:00
|
|
|
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
|
|
|
|
|
2022-03-26 01:45:36 -04:00
|
|
|
prop.setPropClean(true)
|
|
|
|
|
2021-12-16 02:07:35 -05:00
|
|
|
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")
|
2021-12-14 20:11:04 -05:00
|
|
|
|
|
|
|
core:log(log.INFO, "Loaded v"..core.modules.core.version.." successfully")
|
2021-12-16 02:07:35 -05:00
|
|
|
net.start("LSFT-Loaded")
|
|
|
|
net.send()
|
2021-12-14 20:11:04 -05:00
|
|
|
|
|
|
|
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)
|
2021-12-16 02:07:35 -05:00
|
|
|
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
|
2021-12-14 20:11:04 -05:00
|
|
|
|
|
|
|
for i, v in pairs(core.modules) do
|
2021-12-16 02:07:35 -05:00
|
|
|
for commandin, commandthing in pairs(v["commands"]) do
|
2021-12-14 20:11:04 -05:00
|
|
|
if command == commandin then
|
2022-03-26 04:34:57 -04:00
|
|
|
try(
|
|
|
|
function() commandthing.func({unpack(args)}) end,
|
|
|
|
function(err) core:log(log.ERROR, "Error executing command \""..str.."\"!") core:log(log.ERROR, "Reason: "..err["message"]) end
|
|
|
|
)
|
2021-12-14 20:11:04 -05:00
|
|
|
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)
|
|
|
|
|
2021-12-16 02:07:35 -05:00
|
|
|
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
|
2021-12-14 20:11:04 -05:00
|
|
|
end
|
|
|
|
|
2021-12-16 02:07:35 -05:00
|
|
|
print(core.colors.logo, "[L-SFT] ", color, unpack(message))
|
2021-12-14 20:11:04 -05:00
|
|
|
end
|
|
|
|
|
2022-03-26 01:46:18 -04:00
|
|
|
function core:logConsole(...)
|
|
|
|
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
|
|
|
|
|
|
|
|
printConsole(core.colors.logo, "[L-SFT] ", color, unpack(message))
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Get's a player's entity by searching for it via an inputted string
|
|
|
|
function core:get_entity(ply)
|
2022-03-26 15:19:17 -04:00
|
|
|
if ply == nil then
|
|
|
|
return nil
|
|
|
|
elseif type(ply) == "Player" then
|
2022-03-26 01:46:18 -04:00
|
|
|
return ply
|
|
|
|
elseif ply == "^" then
|
|
|
|
return owner()
|
|
|
|
end
|
|
|
|
|
|
|
|
local targets = find.playersByName(ply)
|
|
|
|
|
|
|
|
if #targets == 0 or targets == nil then
|
|
|
|
core:log(log.ERROR, "No targets found!")
|
|
|
|
return nil
|
|
|
|
elseif #targets > 1 then
|
|
|
|
local list = ""
|
|
|
|
for i, v in pairs(target) do
|
|
|
|
list = list..v..", "
|
|
|
|
end
|
|
|
|
|
|
|
|
list:sub(1, -2)
|
|
|
|
core:log(log.ERROR, "Muliple targets found! ("..list..")")
|
|
|
|
return nil
|
|
|
|
end
|
|
|
|
|
|
|
|
return targets[1]
|
|
|
|
end
|
|
|
|
|
2021-12-14 20:11:04 -05:00
|
|
|
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()
|
2021-12-16 02:07:35 -05:00
|
|
|
print(core.defaultconfig.core.colors.logo, "[L-SFT] ", core.defaultconfig.core.colors.info, "Downloading configuration: ", math.round(net.getStreamProgress() * 100, 2), "%")
|
2021-12-14 20:11:04 -05:00
|
|
|
end)
|
|
|
|
|
|
|
|
net.readStream(function(data)
|
|
|
|
timer.remove("ConfigProgress")
|
|
|
|
core:init(json.decode(data))
|
|
|
|
end)
|
|
|
|
else
|
2021-12-16 02:07:35 -05:00
|
|
|
print(core.defaultconfig.core.colors.logo, "[L-SFT] ", core.defaultconfig.core.colors.error, ply:getName().." is trying to give us a config")
|
2021-12-14 20:11:04 -05:00
|
|
|
end
|
|
|
|
end)
|
|
|
|
|
|
|
|
net.receive("LSFT-Get-Config", function()
|
2021-12-16 02:07:35 -05:00
|
|
|
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)
|
|
|
|
|
|
|
|
|
2022-03-26 01:46:47 -04:00
|
|
|
timer.create("CPUCheck", 0.5, 0, function()
|
2021-12-16 02:07:35 -05:00
|
|
|
if quotaAverage() > core.maxCPU then
|
|
|
|
core.maxCPU = quotaAverage()
|
|
|
|
end
|
2021-12-14 20:11:04 -05:00
|
|
|
|
2021-12-16 02:07:35 -05:00
|
|
|
if quotaAverage() > quotaMax() * 0.5 then
|
2022-03-26 01:46:47 -04:00
|
|
|
core:log(log.WARNING, "CPU usage is high! ("..math.round(quotaAverage()*100/quotaMax()).."% remaining)")
|
2021-12-16 02:07:35 -05:00
|
|
|
elseif quotaAverage() > quotaMax() * 0.9 then
|
2022-03-26 01:46:47 -04:00
|
|
|
core:log(log.ERROR, "CPU usage is critically high! ("..math.round(quotaAverage()*100/quotaMax()).."% remaining)")
|
2021-12-16 02:07:35 -05:00
|
|
|
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)
|
|
|
|
|
2022-03-26 01:46:47 -04:00
|
|
|
timer.create("NetCheck", 0.5, 0, function()
|
2021-12-16 02:07:35 -05:00
|
|
|
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)
|
|
|
|
|
2022-03-26 01:46:47 -04:00
|
|
|
timer.create("RAMCheck", 0.5, 0, function()
|
2021-12-16 02:07:35 -05:00
|
|
|
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
|
2022-03-26 04:34:57 -04:00
|
|
|
end)
|