0% found this document useful (0 votes)
142 views18 pages

MonetLoader Script Manager 3.0.0

MonetLoader for Android 3.0.0 is a script manager that allows users to manage scripts, view logs, execute Lua code, and receive notifications. It provides an API for script developers to implement toggle functionality and includes features like a circular buffer for message storage and customizable notifications. The document includes code examples and details about the configuration and usage of the script manager.

Uploaded by

vnpecinha
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
142 views18 pages

MonetLoader Script Manager 3.0.0

MonetLoader for Android 3.0.0 is a script manager that allows users to manage scripts, view logs, execute Lua code, and receive notifications. It provides an API for script developers to implement toggle functionality and includes features like a circular buffer for message storage and customizable notifications. The document includes code examples and details about the configuration and usage of the script manager.

Uploaded by

vnpecinha
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd

-- MonetLoader for Android 3.0.

0
-- Reference script: Script Manager
--
-- For script developers:
-- If you want to allow your script to be toggled from Script Manager, you must
implement the following API in EXPORTS:
-- 1. For "Enabled" checkbox:
-- a. canToggle: return true
-- b. getToggle: return <your toggled status variable>
-- c. toggle: execute any code, and switch <your toggled status variable>
(switching is optional)
-- 2. For "Activate button":
-- a. canToggle: return false
-- b. getToggle: return false
-- c. toggle: execute any code
--
-- Simple example that implements "Enabled" checkbox:
-- local toggled = false
-- EXPORTS = {
-- canToggle = function() return true end,
-- getToggle = function() return toggled end,
-- toggle = function() toggled = not toggled end
-- }
--

-- script info
script_name('Script Manager')
script_version('1.2')
script_version_number(3)
script_author('The MonetLoader Team')
script_description('Script manager that opens on left swipe on radar and provides
ability to manage scripts, view logs, execute Lua code in REPL-like mode and
receive script notifications.')
script_properties('work-in-pause', 'forced-reloading-only') -- work even in pause
and don't reload ourselves on reloadScripts()

-- libs
local levels = require('moonloader').message_prefix
local ffi = require('ffi')
local widgets = require('widgets') -- for WIDGET_(...)
local imgui = require('mimgui')
local faicons = require('fAwesome6')
local cfg = require('jsoncfg')

-- pretty printing ([Link]


table-to-console)

function prettyPrintTable(node)
local cache, stack, output = {},{},{}
local depth = 1
local output_str = "{"

while true do
local size = 0
for k,v in pairs(node) do
size = size + 1
end
local cur_index = 1
for k,v in pairs(node) do
if (cache[node] == nil) or (cur_index >= cache[node]) then

if ([Link](output_str,"}",output_str:len())) then
output_str = output_str .. ","
end

-- This is necessary for working with HUGE tables otherwise we run out of
memory using concat on huge strings
[Link](output,output_str)
output_str = ""

local key
if (type(k) == "string") then
key = "['"..tostring(k).."']"
else
key = "["..tostring(k).."]"
end

if (type(v) ~= "table" and type(v) ~= "string") then


output_str = output_str .. key .. " = "..tostring(v)
elseif (type(v) == "table") then
output_str = output_str .. key .. " = {"
[Link](stack,node)
[Link](stack,v)
cache[node] = cur_index+1
break
else
output_str = output_str .. key .. " = '"..tostring(v).."'"
end

if (cur_index == size) then


output_str = output_str .. "}"
else
output_str = output_str .. ","
end
else
-- close the table
if (cur_index == size) then
output_str = output_str .. "}"
end
end

cur_index = cur_index + 1
end

if (size == 0) then
output_str = output_str .. "}"
end

if (#stack > 0) then


node = stack[#stack]
stack[#stack] = nil
depth = cache[node] == nil and depth + 1 or depth - 1
else
break
end
end

-- This is necessary for working with HUGE tables otherwise we run out of memory
using concat on huge strings
[Link](output,output_str)
output_str = [Link](output)

return output_str
end

-- pretty prints arguments, expanding tables (also supports multiple nils without
omitting them)
function prettyPrint(...)
-- we use select instead of table unpacking in order to handle nil values
correctly
local argc = select('#', ...)
if argc == 0 then
return 'nil'
end

local output_str = ''


for i=1, argc do
local v = select(i, ...)
if type(v) == 'table' then
output_str = output_str .. prettyPrintTable(v)
elseif type(v) == 'string' then
output_str = output_str .. "'" .. v .. "'"
else
output_str = output_str .. tostring(v)
end
if i ~= argc then
output_str = output_str .. ','
end
end

return output_str
end

-- simple ipairs implementation that supports any type

function stateless_iter(a, i)
i = i + 1
local v = a[i]
if v then
return i, v
end
end

function any_ipairs(a)
return stateless_iter, a, 0
end

-- circular buffer class ([Link]

local function rotate_indice(i, n)


return ((i - 1) % n) + 1
end
local circular_buffer = {}

function circular_buffer.reverse_iter(a, i)
i = i - 1
local v = a[i]
if v then
return i, v
end
end

function circular_buffer.reverse_ipairs(self)
return circular_buffer.reverse_iter, self, 0
end

function circular_buffer.filled(self)
return #([Link]) == self.max_length
end

function circular_buffer.push(self, value)


if self:filled() then
local value_to_be_removed = [Link][[Link]]
[Link][[Link]] = value
[Link] = [Link] == self.max_length and 1 or [Link] + 1
else
[Link][#([Link]) + 1] = value
end
end

function circular_buffer.clear(self)
[Link] = {}
[Link] = 1
end

circular_buffer.metatable = {}

-- positive values index from newest to oldest (starting with 1)


-- negative values index from oldest to newest (starting with -1)
function circular_buffer.metatable.__index(self, i)
local history_length = #([Link])
if i == 0 or [Link](i) > history_length then
return nil
elseif i > 0 then
local i_rotated = rotate_indice([Link] - 1 + i, history_length)
return [Link][i_rotated]
else
local i_rotated = rotate_indice([Link] + i, history_length)
return [Link][i_rotated]
end
end

function circular_buffer.metatable.__len(self)
return #([Link])
end

function circular_buffer.new(max_length)
if type(max_length) ~= 'number' or max_length <= 1 then
error("Buffer length must be a positive integer")
end
local instance = {
history = {},
oldest = 1,
max_length = max_length,
push = circular_buffer.push,
filled = circular_buffer.filled,
clear = circular_buffer.clear
}
setmetatable(instance, circular_buffer.metatable)
return instance
end

-- notifications ([Link]

Notifications = {
_version = '0.2',
_list = {},
_COLORS = {
[0] = {back = {0.26, 0.71, 0.81, 1}, text = {1, 1, 1, 1}, icon = {1, 1, 1,
1}, border = {1, 0, 0, 0}},
[1] = {back = {0.26, 0.81, 0.31, 1}, text = {1, 1, 1, 1}, icon = {1, 1, 1,
1}, border = {1, 0, 0, 0}},
[2] = {back = {1, 0.39, 0.39, 1}, text = {1, 1, 1, 1}, icon = {1, 1, 1,
1}, border = {1, 0, 0, 0}},
[3] = {back = {0.97, 0.57, 0.28, 1}, text = {1, 1, 1, 1}, icon = {1, 1, 1,
1}, border = {1, 0, 0, 0}},
[4] = {back = {0, 0, 0, 1}, text = {1, 1, 1, 1}, icon = {1, 1, 1,
1}, border = {1, 0, 0, 0}},
},

TYPE = {
INFO = 0,
OK = 1,
ERROR = 2,
WARN = 3,
DEBUG = 4
},
ICON = {
[0] = faicons('CIRCLE_INFO'),
[1] = faicons('CHECK'),
[2] = faicons('XMARK'),
[3] = faicons('EXCLAMATION'),
[4] = faicons('WRENCH')
}
}

[Link] = function(text, type, time, colors)


[Link](Notifications._list, {
text = text,
type = type or 2,
time = time or 4,
start = [Link](),
alpha = 0,
colors = colors or Notifications._COLORS[type]
})
end
Notifications._TableToImVec = function(tbl)
return imgui.ImVec4(tbl[1], tbl[2], tbl[3], tbl[4])
end

Notifications._BringFloatTo = function(from, to, start_time, duration)


local timer = [Link]() - start_time
if timer >= 0.00 and timer <= duration then
local count = timer / (duration / 100)
return from + (count * (to - from) / 100), true
end
return (timer > duration) and to or from, false
end

[Link](
function() return #Notifications._list > 0 end,
function(self)
[Link] = true

for k, data in ipairs(Notifications._list) do


--==[ UPDATE ALPHA ]==--
if [Link] == nil then Notifications._list[k].alpha = 0 end
if [Link]() - [Link] < 0.5 then
Notifications._list[k].alpha = Notifications._BringFloatTo(0, 1,
[Link], 0.5)
elseif [Link] - 0.5 < [Link]() - [Link] then
Notifications._list[k].alpha = Notifications._BringFloatTo(1, 0, [Link]
+ [Link] - 0.5, 0.5)
end

--==[ REMOVE ]==--


if [Link]() - [Link] > [Link] then
[Link](Notifications._list, k)
end
end

local resX, resY = getScreenResolution()


local sizeX, sizeY = 300 * MONET_DPI_SCALE, 300 * MONET_DPI_SCALE
[Link](imgui.ImVec2(resX * 0.5, resY * 0.5),
[Link], imgui.ImVec2(0.5, 0.5))
[Link](imgui.ImVec2(sizeX, sizeY), [Link])
[Link]('notf_window', _, 0
+ [Link]
+ [Link]
+ [Link]
+ [Link]
+ [Link]
)

local fiveSc = 5 * MONET_DPI_SCALE


local winSize = [Link]()
imgui.SetWindowPosVec2(imgui.ImVec2(resX - 10 * MONET_DPI_SCALE - winSize.x,
resY * 0.4))

for k, data in ipairs(Notifications._list) do


------------------------------------------------
local default_data = {
text = 'text',
type = 0,
time = 1500
}
for k, v in pairs(default_data) do
if data[k] == nil then
data[k] = v
end
end

local c = [Link]()
local p = [Link]()
local DL = [Link]()

local textSize = [Link]([Link])


local iconSize = [Link]([Link][[Link]] or
faicons('XMARK'))
local size = imgui.ImVec2(fiveSc + iconSize.x + fiveSc + textSize.x + fiveSc,
fiveSc + textSize.y + fiveSc)

local winSize = [Link]()


if winSize.x > size.x + 20 * MONET_DPI_SCALE then
[Link](winSize.x - size.x - 8 * MONET_DPI_SCALE)
end

[Link]([Link], [Link])
[Link]([Link], fiveSc)
[Link]([Link],
Notifications._TableToImVec([Link] or
Notifications._COLORS[[Link]].back))
[Link]([Link],
Notifications._TableToImVec([Link] or
Notifications._COLORS[[Link]].border))
[Link]('toastNotf:'..tostring(k)..tostring([Link]), size, true,
[Link] + [Link])
[Link]([Link],
Notifications._TableToImVec([Link] or
Notifications._COLORS[[Link]].icon))
[Link](imgui.ImVec2(fiveSc, size.y / 2 - iconSize.y / 2))
[Link]([Link][[Link]] or faicons('XMARK'))
[Link]()

[Link]([Link],
Notifications._TableToImVec([Link] or
Notifications._COLORS[[Link]].text))
[Link](imgui.ImVec2(fiveSc + iconSize.x + fiveSc, size.y / 2 -
textSize.y / 2))
[Link]([Link])
[Link]()
[Link]()
[Link](2)
[Link](2)
------------------------------------------------
end

[Link]()
end
)
-- global vars

local DEFAULT_CONFIG = { -- default config


crashNotifications = true, -- whether to show script crash notifications or not
scriptMessageNotifications = false, -- whether to show script message
notifications or not
messagesCount = 100, -- count of saved messages
lastCrashesCount = 10, -- count of saved crashed scripts
shellHistoryCount = 50 -- count of saved shell history
}

local config = [Link](DEFAULT_CONFIG) -- simply config


local messages = circular_buffer.new([Link]) -- buffer that stores
last messages
local lastCrashes = circular_buffer.new([Link]) -- buffer that
stores script info about last crashes
local shellHistory = circular_buffer.new([Link]) -- buffer that
stores shell history
local shellInputHistory = circular_buffer.new([Link]([Link] /
2)) -- buffer that stores shell input history
local shellInputHistoryPos = 0 -- current position in shellInputHistory
local scriptCrashInfos = {} -- buffer that stores reasons for script crash
local reloadLastCrashInfos = {} -- buffer that stores crash info that initiated
reload for a given path

local selectedScriptId = -1 -- id of selected script


local selectedScriptExports -- table returned by import on selected script
local wasInLog = false -- set to true when tab is log, used to auto-scroll to
bottom on tab switch
local wasInShell = false -- same, but with shell
local windowState = [Link](false) -- script mgr window is active or not
-- some imgui wrappers
local imScriptStatus = [Link](false) -- ffi variable for script toggling
local imCrashNotifications = [Link]([Link])
local imScriptMessageNotifications =
[Link]([Link])
local imMessagesCount = [Link]([Link])
local imLastCrashesCount = [Link]([Link])
local imShellHistoryCount = [Link]([Link])

local scriptsSearchBuffer = [Link][128]() -- buffer for scripts search


input
local scriptsSearchText = '' -- scripts search input as lua string
local logSearchBuffer = [Link][128]() -- buffer for log search input
local logSearchText = '' -- log search input as lua string
local shellInputBuffer = [Link][512]() -- buffer for shell input

-- utils

-- formats time in seconds into format: xxh xxm xxs (hours and minutes are omitted
if not present)
function formatClock(diff)
diff = [Link](diff)
local seconds = diff % 60
diff = [Link](diff / 60)
local minutes = diff % 60
diff = [Link](diff / 60)
local hours = diff
return (hours > 0 and tostring(hours) .. 'h ' or '') .. (minutes > 0 and
tostring(minutes) .. 'm ' or '') .. tostring(seconds) .. 's'
end

-- [Link]
[Link](function()
[Link]().IniFilename = nil

local config = [Link]()


[Link] = true
[Link] = true

-- bake only needed glyphs in atlas in order to not waste videomemory


local builder = [Link]()
for _, v in pairs([Link]) do
builder:AddText(v)
end
glyphRanges = imgui.ImVector_ImWchar() -- global, because it must be present
until font atlas is built
builder:BuildRanges(glyphRanges)

[Link]().Fonts:AddFontFromMemoryCompressedBase85TTF(faicons.get_font_data_base
85('solid'), 14 * MONET_DPI_SCALE, config, glyphRanges[0].Data) -- load scaled DPI
font

[Link]():ScaleAllSizes(MONET_DPI_SCALE) -- scale default style


end)

-- rendering

-- main window
[Link](
function() return windowState[0] end,
function(self)
[Link](imgui.ImVec2(530 * MONET_DPI_SCALE, 330 *
MONET_DPI_SCALE), [Link])
[Link]('Script Manager para MonetLoader v' .. [Link],
windowState, [Link])

if [Link]('Tabs') then
local didLogRender = false
local didShellRender = false

if [Link]('Scripts') then -- common scripts control


if [Link]('##ScriptsSearch', 'Procurar....',
scriptsSearchBuffer, [Link](scriptsSearchBuffer)) then
scriptsSearchText = [Link](scriptsSearchBuffer):lower()
end
[Link]()
if [Link]('Recarregar tudo') then
[Link]('Confirme o recarregamento de tudol')
end

if [Link]('Confirme o recarregamento de tudol') then


[Link]('Tem certeza de que deseja recarregar todos os scripts?')
if [Link]('Sim', imgui.ImVec2(150 * MONET_DPI_SCALE, 50 *
MONET_DPI_SCALE)) then
reloadScripts()
[Link]('Todos os scripts foram recarregados',
[Link])
[Link]()
end
[Link]()
if [Link]('Não', imgui.ImVec2(150 * MONET_DPI_SCALE, 50 *
MONET_DPI_SCALE)) then
[Link]()
end

[Link]()
end

[Link]('##ScriptsChild') -- child in order to only scroll scripts


imgui.PushStyleVarVec2([Link], imgui.ImVec2(0, 0))
[Link](2, '##ScriptsColumns', false)
[Link]()
local scripts = [Link]()

if imgui.ListBoxHeaderVec2('##ScriptsListBox', imgui.ImVec2(-1, -1)) then


for i, v in ipairs(scripts) do
if [Link]:lower():find(scriptsSearchText, 1, true) then
if [Link]([Link] .. '##' .. tostring([Link]),
selectedScriptId == [Link]) then
selectedScriptId = [Link]
selectedScriptExports = [Link]
end
end
end
[Link]()
end

[Link]()

local scr = [Link](selectedScriptId)


if scr ~= nil then
[Link]('Nome: %s', [Link])
if [Link] ~= [Link] then
[Link]('Nome do arquivo: %s', [Link])
end

local version = [Link]


local version_num = scr.version_num
if #version ~= 0 and version_num ~= 0 then
[Link]('Versão: %s (%g)', version, version_num)
elseif #version == 0 and version_num ~= 0 then
[Link]('Versão: %g', version_num)
elseif #version ~= 0 and version_num == 0 then
[Link]('Versão: %s', version)
end

local authors = [Link]([Link], ', ')


if #authors ~= 0 then
[Link]('Autores: %s', authors)
end
local desc = [Link]
if #desc ~= 0 then
[Link]('Descrição: %s', desc)
end

local url = [Link]


if #url ~= 0 then
[Link]('URL: %s', url)
end

if [Link]('Descarregar') then
scr:unload()
[Link]([Link] .. ':\nDescarregado!',
[Link])
end
[Link]()
if [Link]('Recarregar') then
scr:reload()
[Link]([Link] .. ':\nRecarregado!',
[Link])
end

-- pcall hell in order to not crash Script Manager if selected script


implements invalid API
if [Link] ~= nil and
[Link] ~= nil and [Link] ~= nil then
local status, result = pcall([Link])
if not status or type(result) ~= 'boolean' then
[Link]([Link] .. ':\nError calling canToggle!\nMake
sure it returns a boolean.', [Link])
else
if result then
local status2, toggle = pcall([Link])
if not status2 or type(toggle) ~= 'boolean' then
[Link]([Link] .. ':\nError calling getToggle!\nMake
sure it returns a boolean.', [Link])
else
imScriptStatus[0] = toggle
if [Link]('Habilitado', imScriptStatus) then
local status3 = pcall([Link])
if not status3 then
[Link]([Link] .. ':\nError calling toggle!',
[Link])
end
end
end
else
if [Link]('Activate') then
local status2 = pcall([Link])
if not status2 then
[Link]([Link] .. ':\nError calling toggle!',
[Link])
end
end
end
end
end
else
[Link]('<<<\nSelecione qualquer script à esquerda!')
end

[Link](1)
[Link]()

[Link]()
end

if [Link]('Log') then -- log of recent events


if [Link]('##LogSearch', 'Procurar...', logSearchBuffer,
[Link](logSearchBuffer)) then
logSearchText = [Link](logSearchBuffer):lower()
end
[Link]()
if [Link]('Limpar Histórico') then
messages:clear()
end

[Link]('##LogChild') -- child in order to only scroll text


without scrolling search and etc

for i, v in any_ipairs(messages) do
if v:lower():find(logSearchText, 1, true) then
[Link]('%s', v)
end
end

if [Link]() >= [Link]() or not wasInLog then


[Link](1.0)
end

[Link]()

[Link]()
didLogRender = true
end

if [Link]('Últimas falhas') then -- log of last crashes


[Link]('##LastCrashesChild', imgui.ImVec2(0, 0), true) -- child
in order to only scroll table and for border
[Link](3, '##LastCrashesColumns', true)

[Link]()
[Link]('Nome do Script')
[Link]()
[Link]()
[Link]('Tempo desde o acidente')
[Link]()
[Link]()
[Link]('Ações')
[Link]()
[Link]()

for i, v in circular_buffer.reverse_ipairs(lastCrashes) do
if not [Link] then
[Link]()
[Link]('%s', [Link])
[Link]()
[Link]()
[Link]('%s', formatClock([Link]() - [Link]))
[Link]()

if not [Link] then


if [Link]('Recarregar##' .. tostring(i)) then
reloadLastCrashInfos[[Link]] = v
[Link]([Link])

lua_thread.create(function()
wait(0)
if not [Link] then
[Link]([Link] .. ':\nFalha ao recarregar!',
[Link])
reloadLastCrashInfos[[Link]] = nil
end
end)
end

[Link]()
end

if [Link]('Esconder##' .. tostring(i)) then


[Link] = true
end

[Link]()
[Link]()
end
end

[Link](1)
[Link]()

[Link]()
end

if [Link]('Shell') then -- lua shell


[Link](-1)
if [Link]('##ShellInput', 'Correr....', shellInputBuffer,
[Link](shellInputBuffer), [Link]) then
local text = [Link](shellInputBuffer)
[Link](shellInputBuffer, '')
shellHistory:push('>> ' .. text)
shellInputHistory:push(text)
shellInputHistoryPos = 0

-- first try to load as expression


local chunk, err = load('return prettyPrint(' .. text .. ')')
if not chunk then
-- then as statement
chunk, err = load(text)
end
if not chunk then
-- compilation failed
shellHistory:push('<!> Syntax error: ' .. tostring(err))
else
-- provide repl result
local result, err = pcall(chunk)
if not result then
shellHistory:push('<!> Error: ' .. tostring(err))
else
shellHistory:push(tostring(err))
end
end
end

if [Link]('Acima') then
shellInputHistoryPos = shellInputHistoryPos - 1
if shellInputHistory[shellInputHistoryPos] ~= nil then
[Link](shellInputBuffer,
shellInputHistory[shellInputHistoryPos])
else
shellInputHistoryPos = shellInputHistoryPos + 1
end
end
[Link]()
if [Link]('Abaixo') then
shellInputHistoryPos = shellInputHistoryPos + 1
if shellInputHistoryPos >= 0 then
shellInputHistoryPos = 0
[Link](shellInputBuffer, '')
else
[Link](shellInputBuffer,
shellInputHistory[shellInputHistoryPos])
end
end
[Link]()
if [Link]('Limpar') then
[Link](shellInputBuffer, '')
shellInputHistoryPos = 0
end
[Link]()
if [Link]('Limpar Histórico') then
[Link](shellInputBuffer, '')
shellInputHistoryPos = 0

shellHistory:clear()
shellInputHistory:clear()
end

[Link]('##ShellChild') -- child in order to only scroll text


without scrolling input and etc

for i, v in any_ipairs(shellHistory) do
local doPop = false
if v:sub(1, 3) == '<!>' then
doPop = true
[Link]([Link], imgui.ImVec4(1.0, 0.0, 0.0, 1.0))
end
[Link]('%s', v)
if doPop then
[Link]()
end
end

if [Link]() >= [Link]() or not wasInShell then


[Link](1.0)
end
[Link]()

[Link]()
didShellRender = true
end

if [Link]('Configurações') then -- settings menu


if [Link]('Notificações de falhas', imCrashNotifications) then
[Link] = imCrashNotifications[0]
[Link](config)
end

if [Link]('Notificações de mensagens de script',


imScriptMessageNotifications) then
[Link] = imScriptMessageNotifications[0]
[Link](config)
end

if [Link]('Contagem de mensagens de logs', imMessagesCount, 1, 20)


then
if imMessagesCount[0] < 10 then
imMessagesCount[0] = 10
elseif imMessagesCount[0] > 5000 then
imMessagesCount[0] = 5000
end

[Link] = imMessagesCount[0]
[Link](config)

local newBuffer = circular_buffer.new([Link])

for i, v in any_ipairs(messages) do
newBuffer:push(v)
end

messages = newBuffer
end

if [Link]('Contagem de falhas de logs', imLastCrashesCount, 1, 1)


then
if imLastCrashesCount[0] < 2 then
imLastCrashesCount[0] = 2
elseif imLastCrashesCount[0] > 100 then
imLastCrashesCount[0] = 100
end

[Link] = imLastCrashesCount[0]
[Link](config)

local newBuffer = circular_buffer.new([Link])

for i, v in any_ipairs(lastCrashes) do
newBuffer:push(v)
end

lastCrashes = newBuffer
end
if [Link]('Contagem de histórico do shell', imShellHistoryCount, 1,
20) then
if imShellHistoryCount[0] < 10 then
imShellHistoryCount[0] = 10
elseif imShellHistoryCount[0] > 5000 then
imShellHistoryCount[0] = 5000
end

[Link] = imShellHistoryCount[0]
[Link](config)

local newBuffer = circular_buffer.new([Link])


for i, v in any_ipairs(shellHistory) do
newBuffer:push(v)
end
shellHistory = newBuffer

local newInputBuffer =
circular_buffer.new([Link]([Link] / 2))
for i, v in any_ipairs(shellInputHistory) do
newInputBuffer:push(v)
end
shellInputHistory = newInputBuffer
end

[Link]()
end

[Link]()
wasInLog = didLogRender
wasInShell = didShellRender
end

[Link]()
end
)

-- custom events

-- called whenever a script crashes


function onScriptCrashed(scr, msg)
if [Link] then
[Link]([Link] .. ':\nFalha!', [Link])
end

lastCrashes:push({
name = [Link],
path = [Link],
time = [Link](),
reloaded = false,
hidden = false
})
messages:push('(crash) ' .. [Link] .. ': ' .. msg)
end

-- events
-- script message handler, save them to buffer
function onScriptMessage(msg, scr)
if [Link] then
[Link]([Link] .. ':\n' .. msg, [Link])
end

messages:push('(script) ' .. [Link] .. ': ' .. msg)


end

-- system message handler, get crash info


function onSystemMessage(msg, level, scr)
if level == levels.TYPE_SYSTEM then
if scr ~= nil then
messages:push('(system) ' .. [Link] .. ': ' .. msg)
else
messages:push('(system) ' .. msg)
end
return
end

if scr ~= nil and level == levels.TYPE_ERROR then


if msg:find('Script died due to') and scriptCrashInfos[[Link]] ~= nil then
scriptCrashInfos[[Link]].crashed = true
else
scriptCrashInfos[[Link]] = {
message = msg,
crashed = false
}
end
end
end

-- invoke onScriptCrashed if terminate was called due to script crash


function onScriptTerminate(scr, quit)
if quit then return end

if scriptCrashInfos[[Link]] ~= nil then


if scriptCrashInfos[[Link]].crashed then
onScriptCrashed(scr, scriptCrashInfos[[Link]].message)
end
scriptCrashInfos[[Link]] = nil
end

-- if scr == [Link] then


-- [Link](config)
-- end
end

-- mark script as reloaded in last crashes if it was loaded


function onScriptLoad(scr)
local path = [Link]
if reloadLastCrashInfos[path] ~= nil then
local v = reloadLastCrashInfos[path]
[Link] = true
[Link]([Link] .. ':\nRecarregado!', [Link])
reloadLastCrashInfos[path] = nil
else
for i, v in any_ipairs(lastCrashes) do
if [Link] == path then
[Link] = true
end
end
end
end

-- check for menu opening


function main()
while true do
if isWidgetSwipedLeft(WIDGET_RADAR) then
windowState[0] = not windowState[0]
end
wait(0)
end
end

Common questions

Powered by AI

The Script Manager retains configuration consistency by saving changes to a configuration file using the cfg.save function. When scripts are reloaded, previous configurations are maintained, ensuring that settings like notifications and history counts remain consistent across sessions. This allows for a seamless user experience without configuration loss during script restarts .

ImGui is integral to scripting notification management as it facilitates dynamic UI rendering and real-time updates. Notifications use ImGui widgets to display messages that adapt to user interactions, leveraging features like window positioning and auto-resizing. This integration allows for flexible and responsive notification handling without manual UI redraws .

The Script Manager uses a defined API to handle script toggling. It consists of three functions: canToggle to check if the script can be toggled, getToggle to retrieve the toggle status, and toggle to change the toggle state. These functions are exported in a table to be accessed by the Script Manager interface .

The notification system is designed to be comprehensive and customizable. It categorizes messages into types such as INFO, ERROR, WARN, and provides customization for appearance through color settings using the ImGui library. Notifications are shown and removed dynamically based on timestamps, ensuring timely information relay. The integration with script events allows for efficient communication of status, maintaining user awareness at all times .

The circular buffer implementation ensures efficient data management by maintaining a fixed size. It overwrites old data when new data is added once the buffer reaches capacity. This allows constant time addition and retrieval operations. Moreover, the use of metatable indexing supports both positive and negative indices for efficient retrieval from either end. This strategy ensures optimal and predictable memory and performance efficiency .

The Script Manager employs notifications and log entries to handle errors and crashes by capturing script crashes and displaying alerts. This is immediate but further suggestions include implementing more detailed error logs and possibly integrating recovery options such as automatic attempts to resolve recoverable errors. Extending notification customization could also improve user experience .

The Script Manager employs a function called prettyPrintTable that prints tables in a formatted manner and manages memory usage by inserting each segment of the string into an array and then concatenating these strings at the end. This approach helps avoid the memory overload that could occur if concatenating a large string directly .

Scaling is applied to ensure the UI is consistent across different screen resolutions. This is implemented by scaling the default style using MONET_DPI_SCALE, adjusting all interface elements in relation to screen DPI settings. This scaling is crucial for providing a consistent user experience regardless of the device's display specifications .

User interactions are managed through a series of UI elements powered by the ImGui library. Buttons are used for actions like activating scripts, which are hooked up to functions using event-driven programming. When a user clicks a button, it triggers script-related functions, which modify the toggle state or reload scripts. Popup dialogs are used for confirmation actions, providing an opportunity to prevent unintentional operations .

The shell input management utilizes a circular buffer to maintain and retrieve a history of shell commands, enhancing efficiency. This allows the system to efficiently manage fixed storage for command history, providing constant-time retrieval and minimal latency, even with maximum capacity utilization. This avoids excessive memory usage while maintaining easy navigation through command history .

You might also like