diff --git a/script.lua b/script.lua index 17eaadd..ebfa671 100644 --- a/script.lua +++ b/script.lua @@ -1,3 +1,4 @@ +-- vim: set foldmethod=marker : -- Texture dimensions -- size = 128 factor = size / 64 @@ -125,3 +126,1585 @@ function tick() old_health=player.getHealth() end +-- REPL CODE {{{ +if client.isHost() then + local loadSecrets = false --Disable this if the REPL is slow to load. +--[[>========================================<< INFO >>========================================<[]-- + FIGURA REPL + By: GrandpaScout [STEAM_1:0:55009667] + Version: 4.1.1 + Compatibility: >= Figura 0.0.8 + Description: + A REPL for use in Figura 0.0.8 or later. + Contains formatting for types, table printing, hover data, and many other useful tools. + Is also themeable! +--[]>======================================<< END INFO >>======================================<]]-- + + --Create a completely seperated string table. + local string = {} + for k,v in pairs(_G.string) do + string[k] = v + end + + local function checkSMT() + return pcall(function() + ---@diagnostic disable: unused-local + local str = "%s" + local str2 = "I" + local a, b + a = str:byte(1,3) + a = str:find("h", 1, true) + a = str:format("hello") + for _ in str:gmatch("h") do end + a = str:gsub("h", "i", 2) + a = str:len() + a = str:lower() + a = str:match("h", 2) + a = str:rep(5, "//") + a = str:reverse() + a = str:sub(1, 4) + a = str:upper() + ---@diagnostic enable: unused-local + end) + end + --The REPL *requires* a functional string metatable. + --This will replace a missing one with a substitute. + if not checkSMT() then + local t = {} + for k,f in pairs(string) do + t[k] = f + end + getmetatable("").__index = t + end + + ---@type any #Shut up type hints for this value. + local Infinity = math.huge --An infinite value, for convenience. + --[=========================================[ CONFIG ]=========================================]-- + + local repl_theme = { + repl = { --Generic REPL text + --[[Normal text. | color ]] default = "white", + --[[INPUT: | color ]] input = "white", + --[[RETURNS: | color ]] returns = "white", + --[[REPL: Notice | color ]] notice = "white", + --[[REPL: Error | color ]] error = "red", + --[[return | color ]] repl_return = "light_purple", + --[[User Code. | color ]] user_input = "white", + }, + any = { -- Any values + --[[Prop: | color ]] h_property = "dark_gray", + --[[Metatable: {} | number ]] meta_len = 16 + }, + null = { -- Nil values + --[[nil | color ]] default = "gray", + --[[(no value?) | color ]] no_value = "dark_gray" + }, + boolean = { -- Booleans + --[[true false | color ]] default = "yellow", + --[[true color | color ]] t = "dark_green", + --[[false color | color ]] f = "dark_red", + --[[true symbol | string ]] true_char = "☑", + --[[false symbol | string ]] false_char = "☒" + }, + number = { -- Numbers + --[[123 | color ]] default = "blue", + --[[(0x7B) | color ]] hex = "dark_blue", + --[[0b10 | color ]] bin = "dark_blue", + --[[0o71 | color ]] oct = "dark_blue", + --[[0x, 0X, #, etc. | string ]] hex_prefix = "0x", + --[[0b, 0B, etc. | string ]] bin_prefix = "0b", + --[[0o, 0O, 0, etc. | string ]] oct_prefix = "0o" + }, + string = { -- Strings + --[["abc" | color ]] default = "red", + --[[\r\n§ | color ]] escaped = "dark_red", + --[[\ | color ]] slash = "dark_gray", + --[[(# bytes) | color ]] bytes = "dark_red", + --[[# characters | color ]] characters = "dark_red", + --[[... | color ]] len_limit = "gray", + --[[= "hello wo..." | number ]] value_size = 256, + --[["hello worl..." | number ]] max_size = Infinity, + --[["Hover Da..." | number ]] max_h_size = 4096, + --[[\0 -> ∅ | boolean]] use_symbols = true + }, + table = { -- Tables + --[[table: 1234abcd | color ]] default = "aqua", + --[[(# indexes) | color ]] indexes = "dark_aqua", + --[[{ } | color ]] bracket = "dark_gray", + --[[[ ] | color ]] key_bracket = "dark_gray", + --[[= | color ]] equals = "dark_gray", + --[[ · · · (# more) | color ]] line_limit = "gray", + --[[ | color ]] root = "white", + --[[ | color ]] duplicate = "aqua", + --[[["string"] = | number ]] skey_len = 16, + --[[max table depth | number ]] max_indent = 1, + --[[max table len | number ]] max_length = Infinity, + --[[ · · · } | number ]] more_len = 48, + --[[Contents: {} | number ]] content_len = 32 + }, + func = { -- Functions + --[[function: | color ]] default = "light_purple", + --[[avatar | color ]] script = "dark_purple", + --[[:123-167 | color ]] lines = "dark_gray", + --[[builtin: | color ]] builtin = "dark_gray", + --[[figura: | color ]] figura = "dark_gray", + --[[unknown: | color ]] unknown = "dark_gray", + --[[(# bytes) | color ]] bytes = "dark_purple", + --[[Lua | color ]] lua = "blue", + --[[(JAVA) | color ]] java = "gold" + }, + userdata = { + --[[userdata: | color ]] default = "gray", + --[[1 stick | color ]] value = "gray" + }, + thread = { -- Threads + --[[thread: 1234abc | color ]] default = "green", + --[[(status) | color ]] parentheses = "dark_green", + --[[Running | color ]] running = "green", + --[[Suspended | color ]] suspended = "gold", + --[[Normal | color ]] normal = "dark_aqua", + --[[Dead | color ]] dead = "dark_red" + }, + vector = { -- Vectors + --[[1.23 | color ]] default = "white", + --[[< > | color ]] bracket = "dark_gray", + --[[, | color ]] seperator = "dark_gray", + --[[(#/6 indexes) | color ]] indexes = "gray", + --[[123.45 | color ]] length = "gray", + }, + other = { -- Unknown types. + --[[stringified val | color ]] default = "white", + --[[(type) | color ]] type = "gray" + } + } + --[=======================================[ END CONFIG ]=======================================]-- + + local replcatmt = { + __metatable = false, + __newindex = function(self, key, value) + if self[key] == nil then error("cannot change non-existent Theme Setting") end + if type(value) == "string" then + rawset(self, key, value:gsub("([\\\"])", "\\%1")) + else + rawset(self, key, value) + end + end, + __index = { + NewSetting = function(self, name, value) + if self[name] ~= nil then + rawset(self, name, value or false) + end + end + } + } + + for _,c in pairs(repl_theme) do + setmetatable(c, replcatmt) + end + + setmetatable(repl_theme, { + __metatable = false, + __newindex = function(self, key) + if not self[key] then + error("cannot add new Theme Setting category") + else + error("cannot replace Theme Setting category") + end + end, + __index = { + NewCategory = function(self, name) + if not self[name] then + rawset(self, name, setmetatable({}, replcatmt)) + end + end + } + }) + + local + rtr, rta, rtx, + rtb, rtn, rts, + rtt, rtf, rtu, + rtc, rtv, rto + = + repl_theme.repl, repl_theme.any, repl_theme.null, + repl_theme.boolean, repl_theme.number, repl_theme.string, + repl_theme.table, repl_theme.func, repl_theme.userdata, + repl_theme.thread, repl_theme.vector, repl_theme.other + + local strrep = { + all = '([\0\a\b\f\n\r\t\v\\"])', --∅♪←⊻↓⏮⇄⇵ + ["\0"] = {"0", "∅"}, + ["\a"] = {"a", "♪"}, + ["\b"] = {"b", "←"}, + ["\f"] = {"f", "⊻"}, + ["\n"] = {"n", "↓"}, + ["\r"] = {"r", "⏮"}, + ["\t"] = {"t", "⇄"}, + ["\v"] = {"v", "⇵"}, + ["\\"] = {"\\\\", "\\\\"}, + ["\""] = {'\\"', '\\"'} + } + + function strrep.toStr(x) + return ('",{"text":"\\\\","color":"%s"},{"text":"%s","color":"%s"},"'):format( + rts.slash, + strrep[x][1], + rts.escaped + ) + end + + function strrep.toSym(x) + return ('",{"text":"%s","color":"%s"},"'):format( + strrep[x][2], + rts.escaped + ) + end + + local keyrank = { + boolean = 0, number = 1, string = 2, table = 3, + ["function"] = 4, thread = 5, vector = 6, userdata = 7, other = 99 + } + + local function tblsort(a, b) + local ar, br = keyrank[type(a)] or keyrank.other, keyrank[type(b)] or keyrank.other + if ar == br then + if ar == 1 then + return a < b + else + return tostring(a) < tostring(b) + end + else + return ar < br + end + end + + local figuraFIDs = { + PingFunction = true + } + + H = {} + local H = H + setmetatable(H, { + __pow = function(self, ind) + if self ~= H then + error("index from the right side of the history list") + elseif type(ind) ~= "number" then + error("quick-history only works with a number") + else + local x,y = tostring(ind):match("^(%-?%d*)%.?(%d-)$") + x,y = tonumber(x) or 1, tonumber(y) + local res = self[x == 0 and 1 or #self-x+1] + return res and (y and res[y] or res) or nil + end + end + }) + + O = {} + local O = O + local Otypes = {number = true, ["function"] = true, table = true, userdata = true, thread = true, vector = true} + local Omt = { + __type = "PointersList", + __index = { + N = {}, + Nindex = {} + } + } + local Oindex, OindexN, OindexNi = Omt.__index, Omt.__index.N, Omt.__index.Nindex + function Omt:__newindex(key) + local t = type(key) + if Otypes[t] then + if t == "number" then + if not OindexNi[key] then + OindexN[#Oindex.N+1] = key + OindexNi[key] = #Oindex.N + end + elseif not Oindex[key] then + Oindex[#Oindex+1] = key + Oindex[key] = #Oindex + end + end + end + function Omt:__len() return #Oindex end + setmetatable(O, Omt) + + local JSON = {} do + local function PointersListHover(x, hasContents) + local xmt = getmetatable(x).__index + local str = ('{"text":"PointerList","color":"%s"},{"text":" (table)\n","color":"%s"},[{"text":"Pointers: ","color":"%s"},{"text":"%d","color":"%s"}'):format( + rtt.default, + rtt.indexes, + rta.h_property, + #xmt, rtt.indexes + ) + if not hasContents then + str = str .. ',"\n\nContents: "' .. JSON.stringify.custom.PointersList(x, true, true, { + length = rtt.content_len, indent = "single" + }) + end + return ('{"action":"show_text","value":[%s]]}'):format(str) + end + + local function PointersListMoreHover(x, tbl, i) + local strs = { + ('{"text":" · · ·","color":"%s"}'):format(rtt.line_limit) + } + for j = i+1, #tbl do + local v = x[j] + strs[#strs+1] = (',"\n "%s,{"text":" = ","color":"%s"}%s'):format( + JSON.stringify.number(j, false, true), + rtt.equals, + JSON.stringify.any(v, true, true, {indent = false}) + ) + if j >= (i+rtt.more_len) and j ~= #tbl then + strs[#strs+1] = (',{"text":"\n · · · (%d more)","color":"%s"}'):format( + #tbl - j, rtt.line_limit + ) + break + end + end + return ('{"action":"show_text","value":[%s,{"text":"\n]","color":"%s"}]}'):format( + table.concat(strs), rtt.bracket + ) + end + + local function HistoryHover(x, hasContents) + --Not yet. + end + + JSON.stringify = { + ---@type table + custom={ + ---@param x table + ---@param detail? string + ---@param inHover? boolean + ---@param options? {indent?:number|"false", DONE?: table, length?: number, max?: boolean} + PointersList = function(x, detail, inHover, options) + local xmt = getmetatable(x).__index + local indent + if options.indent == false then + indent = rtt.max_indent + 1 + else + indent = tonumber(options.indent) and math.max(options.indent, 0) or 1 + end + local contents = indent <= rtt.max_indent + local str = (',[{"text":"PointerList: %s","color":"%s"%s}'):format( + tostring(x):match("^table: (%x%x?%x?%x?%x?%x?%x?%x?)$") or "???", + rtt.default, + not inHover and (',"insertion":"O","hoverEvent":' .. PointersListHover(x, contents)) or "" + ) + if contents then str = str .. (',[{"text":" [","color":"%s"}'):format(rtt.bracket) end + if detail then + str = str .. (',{"text":" (%d pointers)","color":"%s"}'):format( + #xmt, rtt.indexes + ) + end + if contents then + local strs = {} + for i,v in ipairs(xmt) do + strs[#strs+1] = (',"\n%s"%s,{"text":" = ","color":"%s"}%s'):format( + (" "):rep(indent), + JSON.stringify.number(i, false, inHover), + rtt.equals, + JSON.stringify.any(v, true, inHover, {indent = false}) + ) + if options.length and (i >= options.length) and ((#xmt - i) ~= 0) then + if inHover then + strs[#strs+1] = (',{"text":"\n%s · · · (%d more)","color":"%s"}'):format( + (" "):rep(indent), #xmt - i, rtt.line_limit + ) + else + strs[#strs+1] = (',{"text":"\n%s · · · (%d more)","color":"%s","hoverEvent":%s}'):format( + (" "):rep(indent), #xmt - i, rtt.line_limit, PointersListMoreHover(x, Oindex, i) + ) + end + break + end + end + str = str .. ('%s,"\n%s]"]'):format( + table.concat(strs), (" "):rep(math.max(indent-1, 0)) + ) + end + return str .. "]" + end + }, + + ---@param x any + ---@param detail? string + ---@param inHover? boolean + ---@param options? {indent?:number|"false", DONE?: table, length?: number, max?: boolean} + ---@return string + any = function(x, detail, inHover, options) + options = options or {} + local t = type(x) + if t == "string" then + return JSON.stringify.string(x, detail, inHover, options.length) + elseif t == "table" then + local mt = getmetatable(x) + local mtt = type(mt) == "table" and mt.__type or nil + if mtt and JSON.stringify.custom[mtt] then + return JSON.stringify.custom[mtt](x, detail, inHover, options) + else + return JSON.stringify.table(x, detail, inHover, options.indent, options.length, options.DONE) + end + elseif t == "vector" then + return JSON.stringify.vector(x, detail, inHover, options.max) + else + return (JSON.stringify[t] or JSON.stringify.other)(x, detail, inHover) + end + end, + ---@param inHover? boolean + ---@return string + ["nil"] = function(_, _, inHover) + return (',{"text":"nil","color":"%s"%s}'):format( + rtx.default, + not inHover and (',"insertion":"nil","hoverEvent":%s'):format(JSON.hoverData["nil"]()) or "" + ) + end, + ---@param x boolean + ---@param detail? boolean + ---@param inHover? boolean + ---@return string + boolean = function(x, detail, inHover) + local str = (',[{"text":"%s","color":"%s"%s}'):format( + tostring(x), rtb.default, + not inHover and (',"insertion":"%s","hoverEvent":%s'):format( + tostring(x), JSON.hoverData.boolean(x) + ) or "" + ) + if detail then + str = str .. (',{"text":" %s","color":"%s"}'):format( + x and rtb.true_char or rtb.false_char, + x and rtb.t or rtb.f + ) + end + return str .. "]" + end, + ---@param x number + ---@param detail? boolean + ---@param inHover? boolean + ---@return string + number = function(x, detail, inHover) + local unsafenum = tonumber(tostring(x)) ~= x + local insert = x + if unsafenum and not O.Nindex[x] then + O[x] = true + if not inHover then insert = "O.N[" .. O.Nindex[x] .. "]" end + end + local str = (',[{"text":"%s","color":"%s"%s}'):format( + tostring(x), rtn.default, + not inHover and (',"insertion":"%s","hoverEvent":%s'):format( + insert, JSON.hoverData.number(x) + ) or "" + ) + if detail and math.floor(x) == x and x-1 ~= x then + str = str .. (',{"text":" (%s%X)","color":"%s"}'):format( + rtn.hex_prefix, x, rtn.hex + ) + end + return str .. "]" + end, + ---@param x string + ---@param detail? boolean + ---@param inHover? boolean + ---@param length? number + ---@return string + string = function(x, detail, inHover, length) + length = tonumber(length) + local xstr + if not length or (length <= 0) or (length >= #x) then + xstr = x + length = false + else + xstr = x:sub(1, length-4) + end + + local firstmatch = xstr:find(strrep.all) or xstr:find("§") + local str + if firstmatch then + str = xstr + :gsub( + strrep.all, + rts.use_symbols and strrep.toSym or strrep.toStr + ) + :gsub( + "§(.)", + ('",{"text":"ƒ","color":"%s"},"§%%1%%1§r'):format(rts.escaped) + ) + str = (',[{"text":"\\"%s","color":"%s"%s}'):format( + str:sub(1, firstmatch-1), rts.default, + not inHover and (',"insertion":"\\"%s\\"","hoverEvent":%s'):format( + x + :gsub(strrep.all, function(c) return "\\\\" .. strrep[c][1] end) + :gsub("§", "\\\\xC2\\\\xA7") + :gsub("([\1\2\3\4\5\6\14\15\16\17\18\19\20\21\22\23\24\25\26\27\28\29\30\31\127])", function(c) return "\\\\" .. string.byte(c) end), + JSON.hoverData.string(x) + ) or "" + ) .. str:sub(firstmatch+1) + if str:find(',"$') then + str = str:sub(1, -3) .. (length and (',{"text":" · · · ","color":"%s"},"\\""'):format(rts.len_limit) or ',"\\""') + else + str = str .. (length and ('",{"text":" · · · ","color":"%s"},"\\""'):format(rts.len_limit) or '\\""') + end + else + str = (',[{"text":"\\"%s","color":"%s"%s}%s,"\\""'):format( + xstr, rts.default, + not inHover and (',"insertion":"\\"%s\\"","hoverEvent":%s'):format( + x + :gsub(strrep.all, function(c) return "\\\\" .. strrep[c][1] end) + :gsub("§", "\\\\xC2\\\\xA7") + :gsub("([\1\2\3\4\5\6\14\15\16\17\18\19\20\21\22\23\24\25\26\27\28\29\30\31\127])", function(c) return "\\\\" .. string.byte(c) end), + JSON.hoverData.string(x) + ) or "", + length and (',{"text":" · · · ","color":"%s"}'):format(rts.len_limit) or "" + ) + end + if detail then + str = str .. (',{"text":" (%d byte%s)","color":"%s"}'):format( + #x, #x ~= 1 and "s" or "", rts.bytes + ) + end + return str .. "]" + end, + ---@param x table + ---@param detail? boolean + ---@param inHover? boolean + ---@param indent? "false"|number|'"single"' + ---@param length? number + ---@param DONE? table + ---@return string + table = function(x, detail, inHover, indent, length, DONE) + local noindent + if indent == false then + indent = rtt.max_indent + 1 + elseif indent == "single" then + noindent = true + indent = 1 + end + indent = indent == nil and 1 or math.max(indent, 0) + if not O[x] then O[x] = true end + local insert = "O[" .. O[x] .. "]" + local contents = indent <= rtt.max_indent + local xlen = 0 + if not inHover or detail then + for _ in pairs(x) do --Iterate the table for *every* key to get the real size. + xlen = xlen + 1 + end + if xlen == 0 then xlen = tonumber(#x) or 0 end --If a table cannot be iterated, try getting the length. If that fails, use 0. + end + local str = (',[{"text":"%s","color":"%s"%s}'):format( + tostring(x), rtt.default, + not inHover and (',"insertion":"%s","hoverEvent":%s'):format( + insert, JSON.hoverData.table(x, contents, xlen) + ) or "" + ) + if contents then str = str .. (',{"text":" {","color":"%s"}'):format(rtt.bracket) end + if detail then + str = str .. (',{"text":" (%d index%s)","color":"%s"}'):format( + xlen, xlen ~= 1 and "es" or "", rtt.indexes + ) + end + if contents and not next(x) then + str = str .. (',{"text":"%s}","color":"%s"}'):format( + detail and " " or "", + rtt.bracket + ) + contents = false + end + str = str .. "]" + if not DONE then --DONE handles recursion. + DONE = {} + DONE.root = x + DONE[x] = true + elseif DONE.root == x then + str = str .. (',{"text":" ","color":"%s"}'):format(rtt.root) + elseif DONE[x] then + str = str .. (',{"text":" ","color":"%s"}'):format(rtt.duplicate) + else + DONE[x] = true + end + if contents then + local keys = {} + for k in pairs(x) do --Get all keys and sort them. + keys[#keys+1] = k + end + table.sort(keys, tblsort) + + local strs = {} + for i,k in ipairs(keys) do + local v = x[k] + strs[#strs+1] = (',[{"text":"\n%s[","color":"%s"}%s,"]"],{"text":" = ","color":"%s"}%s'):format( + noindent and " " or (" "):rep(indent*2), rtt.key_bracket, + JSON.stringify.any(k, false, inHover, { + length = rtt.skey_len, indent = false, max = false + }), + rtt.equals, + JSON.stringify.any(v, true, inHover, { + indent = ((not DONE[v] and not noindent) and (indent + 1) or false), + length = rts.value_size, + DONE = DONE + }) + ) + if length and (i >= length) and ((#keys - i) ~= 0) then --If the line limit is hit, stop the table early. + if inHover then + strs[#strs+1] = (',{"text":"\n%s · · · (%d more)","color":"%s"}'):format( + (" "):rep(indent), #keys - i, rtt.line_limit + ) + else + strs[#strs+1] = (',{"text":"\n%s · · · (%d more)","color":"%s","hoverEvent":%s}'):format( + (" "):rep(indent), #keys - i, rtt.line_limit, JSON.hoverData.tableMore(x, keys, i) + ) + end + break + end + end + str = str .. ('%s,{"text":"\n%s}","color":"%s"}'):format( + table.concat(strs), (" "):rep(math.max(indent-1, 0)), rtt.bracket + ) + end + return str + end, + ---@param x function + ---@param detail? boolean + ---@param inHover? boolean + ---@return string + ["function"] = function(x, detail, inHover) + local s, dump = pcall(string.dump, x) + local insert + if not inHover then + if not O[x] then O[x] = true end + insert = "O[" .. O[x] .. "]" + end + local str + if s then + local fname, flines = tostring(x):match("^function: ([^:]+)(:%d+%-%d+)$") + str = (',[{"text":"function:","color":"%s"%s},{"text":" %s","color":"%s"},{"text":"%s","color":"%s"}'):format( + rtf.default, + not inHover and (',"insertion":"%s","hoverEvent":%s'):format( + insert, JSON.hoverData["function"](x, #dump) + ) or "", + fname:gsub("([\\\"])", "\\%1"), rtf.script, + flines, rtf.lines + ) + else + local fid = tostring(x):match(" ?([%w_]+)$") + local ftype = fid and ( + (tonumber(fid) or figuraFIDs[fid]) and "figura" or "builtin" + ) or "unknown" + str = (',[{"text":""%s},[{"text":"function: ","color":"%s"},{"text":"%s:","color":"%s"},"%s"]'):format( + not inHover and (',"insertion":"%s","hoverEvent":%s'):format( + insert, JSON.hoverData["function"](x) + ) or "", + rtf.default, + ftype, rtf[ftype], + (fid or ""):gsub("([\\\"])", "\\%1") + ) + end + if detail then + if s then + str = str .. (',{"text":" (%d byte%s)","color":"%s"}'):format( + #dump, #dump ~= 1 and "s" or "", rtf.bytes + ) + else + str = str .. (',{"text":" (JAVA)","color":"%s"}'):format(rtf.java) + end + end + return str .. "]" + end, + ---@param x userdata + ---@param inHover? boolean + ---@return string + userdata = function(x, _, inHover) + local ustr = tostring(x):gsub("([\\\"])", "\\%1") + local insert + if not inHover then + if not O[x] then O[x] = true end + insert = "O[" .. O[x] .. "]" + end + if ustr:match("^userdata: ") then + ustr = ustr:sub(11) + end + return (',[{"text":"userdata: ","color":"%s"%s},{"text":"%s","color":"%s"}]'):format( + rtu.default, + not inHover and (',"insertion":"%s","hoverEvent":%s'):format( + insert, JSON.hoverData.userdata(x) + ) or "", + ustr, rtu.value + ) + end, + ---@param x thread + ---@param detail? boolean + ---@param inHover? boolean + ---@return string + thread = function(x, detail, inHover) + local insert + local status + if detail or not inHover then status = coroutine.status(x) end + if not inHover then + if not O[x] then O[x] = true end + insert = "O[" .. O[x] .. "]" + end + local str = (',[{"text":"%s","color":"%s"%s}'):format( + tostring(x), rtc.default, + not inHover and (',"insertion":"%s","hoverEvent":%s'):format( + insert, JSON.hoverData.thread(x, status) + ) or "" + ) + if detail then + str = str .. (',[{"text":" (","color":"%s"},{"text":"%s","color":"%s"},")"]'):format( + rtc.parentheses, + status:gsub("^.", string.upper), rtc[status] + ) + end + return str .. "]" + end, + ---@param x Vector + ---@param detail? boolean + ---@param inHover? boolean + ---@param max? boolean + ---@return string + vector = function(x, detail, inHover, max) + max = max == nil or max + local insert + if not inHover then + if not O[x] then O[x] = true end + insert = "O[" .. O[x] .. "]" + end + local i = 1 + for j=6,1,-1 do + if x[j] ~= 0 then i = j break end + end + + local strs = {} + if max then + for j = 1, i do + strs[#strs+1] = (',"%f"'):format(x[j]) + end + else + for j = 1, i do + local fstr = tostring(x[j]) + local fsub = fstr:sub(1, (fstr:find("%..*$") or #fstr) + 5) + strs[#strs+1] = (',"%s%s"'):format( + fsub, (#fstr > #fsub) and "..." or "" + ) + end + end + strs[1] = (',[{"text":""%s},[{"text":"<","color":"%s"},[{"text":%s,"color":"%s"}'):format( + not inHover and (',"insertion":"%s","hoverEvent":%s'):format( + insert, JSON.hoverData.vector(x) + ) or "", + rtv.bracket, + strs[1]:sub(2), rtv.default + ) + strs[#strs] = strs[#strs] .. '],">"]' + + local sep = (',{"text":",","color":"%s"}'):format(rtv.seperator) + local str = table.concat(strs, sep) + + if detail then + str = str .. (',{"text":" (%d/6 indexes)","color":"%s"}'):format( + i, rtv.indexes + ) + end + return str .. "]" + end, + ---@param x any + ---@param detail? boolean + ---@param inHover? boolean + ---@return string + other = function(x, detail, inHover) + local str = (',[{"text":"%s","color":"%s"%s}'):format( + tostring(x):gsub("([\\\"])", "\\%1"), rto.default, + not inHover and (',"hoverEvent":' .. JSON.hoverData.other(x)) or "" + ) + if detail then + str = str .. (',{"text":" (%s)","color":"%s"}'):format( + type(x), rto.type + ) + end + return str .. "]" + end + } + local o2b = { + ["0"] = "000", ["1"] = "001", ["2"] = "010", ["3"] = "011", + ["4"] = "100", ["5"] = "101", ["6"] = "110", ["7"] = "111" + } + local vectorObj = { + asTable = 1, toDeg = 2, toRad = 3, angleTo = 4, cross = 5, dot = 6, normalized = 7, + getLength = 8, distanceTo = 9 + } + function JSON.stringify.vectorMethods() + local str = (',{"text":"table: LuaVector","color":"%s"},{"text":" {","color":"%s"},{"text":" (9 indexes)","color":"%s"}'):format( + rtt.default, + rtt.bracket, + rtt.indexes + ) + local keys = {} + for k in pairs(vectorObj) do keys[#keys+1] = k end + table.sort(keys) + local strs = {} + for _, k in ipairs(keys) do + local v = vectorObj[k] + strs[#strs+1] = (',[{"text":"\n [","color":"%s"}%s,"]"],{"text":" = ","color":"%s"},[{"text":"function: ","color":"%s"},{"text":"figura:","color":"%s"},"%s"],{"text":" (JAVA)","color":"%s"}'):format( + rtt.key_bracket, + JSON.stringify.any(k, false, false, {length = rtt.skey_len, indent = false, max = false}), + rtt.equals, + rtf.default, + rtf.figura, + v, + rtf.java + ) + end + return str .. ('%s,{"text":"\n}","color":"%s"}'):format( + table.concat(strs), + rtt.bracket + ) + end + JSON.hoverData = { + ["nil"] = function() + return ('{"action":"show_text","value":[{"text":"Nil\nnil","color":"%s"}]}'):format(rtx.default) + end, + boolean = function(x) + return ('{"action":"show_text","value":[{"text":"Boolean\n","color":"%s"},{"text":"%s","color":"%s"}]}'):format( + rtb.default, + tostring(x), + x and rtb.t or rtb.f + ) + end, + number = function(x) + local str = ('{"text":"Number\n%s","color":"%s"}'):format( + tostring(x), + rtn.default + ) + if math.floor(x) == x and math.abs(x) <= 0x7FFFFFFFFFFFFFFF then + local sign = x < 0 and "-" or "" + x = math.abs(x) + local ostr = ("%o"):format(x) + str = str .. (',[{"text":"\nHex: ","color":"%s"},{"text":"%s%s%x\n","color":"%s"},"Oct: ",{"text":"%s%s%s\n","color":"%s"},"Bin: ",{"text":"%s%s%s","color":"%s"}]'):format( + rta.h_property, + sign, rtn.hex_prefix, x, rtn.hex, + sign, rtn.oct_prefix, ostr, rtn.oct, + sign, rtn.bin_prefix, ostr:gsub(".", o2b):gsub("^0+", "", 1), rtn.bin + ) + end + return ('{"action":"show_text","value":[%s]}'):format(str) + end, + string = function(x) + local chars = 0 + for i = 1, #x do + if math.floor(x:byte(i) * 0.015625) ~= 2 then chars = chars + 1 end + end + local mt = getmetatable("") + return ('{"action":"show_text","value":[{"text":"String\n","color":"%s"}%s,[{"text":"\nBytes: ","color":"%s"},{"text":"%d\n","color":"%s"},"Characters: ",{"text":"%d\n\n","color":"%s"},"Metatable: "%s]]}'):format( + rts.default, + JSON.stringify.string(x, false, true, rts.max_h_size), + rta.h_property, + #x, rts.bytes, + chars, rts.characters, + JSON.stringify.any(mt, true, true, { + indent = "single", + length = type(mt) == "string" and rts.value_size or rta.meta_len + }) + ) + end, + table = function(x, contentVisible, size) + local mt = getmetatable(x) + local str = ('{"text":"Table\n%s\n","color":"%s"},[{"text":"Indexes: ","color":"%s"},{"text":"%d\n\n","color":"%s"},"Metatable: "%s'):format( + tostring(x), rtt.default, + rta.h_property, + size, rtt.indexes, + JSON.stringify.any(mt, true, true, { + indent = "single", + length = type(mt) == "string" and rts.value_size or rta.meta_len + }) + ) + if not contentVisible then + str = str .. (',"\n\nContents: "' .. JSON.stringify.table(x, false, true, "single", rtt.content_len)) + end + return ('{"action":"show_text","value":[%s]]}'):format(str) + end, + tableMore = function(x, keys, i) + local strs = { + ('{"text":" · · ·","color":"%s"}'):format(rtt.line_limit) + } + for j = i+1, #keys do + local k = keys[j] + local v = x[k] + strs[#strs+1] = (',[{"text":"\n [","color":"%s"}%s,"]"],{"text":" = ","color":"%s"}%s'):format( + rtt.key_bracket, + JSON.stringify.any(k, false, true, { + indent = false, length = rtt.skey_len, max = false + }), + rtt.equals, + JSON.stringify.any(v, true, true, { + indent = false, length = rts.value_size + }) + ) + if j >= (i+rtt.more_len) and j ~= #keys then + strs[#strs+1] = (',{"text":"\n · · · (%d more)","color":"%s"}'):format( + #keys - j, rtt.line_limit + ) + break + end + end + return ('{"action":"show_text","value":[%s,{"text":"\n}","color":"%s"}]}'):format( + table.concat(strs), rtt.bracket + ) + end, + ["function"] = function(x, size) + local str = ('{"text":"Function\n","color":"%s"}%s,[{"text":"\nSource: ","color":"%s"},{"text":"%s","color":"%s"}'):format( + rtf.default, + JSON.stringify["function"](x, false, true), + rta.h_property, + size and "Lua" or "Java", size and rtf.lua or rtf.java + ) + if size then + str = str .. (',"\nBytes: ",{"text":"%d","color":"%s"}'):format( + size, rtf.bytes + ) + end + return ('{"action":"show_text","value":[%s]]}'):format(str) + end, + userdata = function(x) + return ('{"action":"show_text","value":[{"text":"Userdata\n","color":"%s"},{"text":"%s","color":"%s"}]}'):format( + rtu.default, + tostring(x):gsub("([\\\"])", "\\%1"), rtu.value + ) + end, + thread = function(x, status) + return ('{"action":"show_text","value":[{"text":"Thread\n%s\n","color":"%s"},{"text":"Status: ","color":"%s"},{"text":"%s","color":"%s"}]'):format( + tostring(x), rtc.default, + rta.h_property, + status, rtc[status] + ) + end, + vector = function(x) + local str = ('{"text":"Vector\n","color":"%s"}%s,[{"text":"\nLength: ","color":"%s"},{"text":"%f\n","color":"%s"}'):format( + rtv.default, + JSON.stringify.vector(x, false, true, true), + rta.h_property, + x.getLength(), rtv.length + ) + if + (x[1] >= 0 and x[1] <= 1) and + (x[2] >= 0 and x[2] <= 1) and + (x[3] >= 0 and x[3] <= 1) + then + local rgb_r,rgb_g,rgb_b = math.floor(x[1]*255), math.floor(x[2]*255), math.floor(x[3]*255) + local rgb_hsv = vectors.rgbToHSV(x) + local rgb_h,rgb_s,rgb_v = math.floor(rgb_hsv[1]*360)%360, math.floor(rgb_hsv[2]*10000)*0.01, math.floor(rgb_hsv[3]*10000)*0.01 + + local hsv_h, hsv_s, hsv_v = math.floor(x[1]*360)%360, math.floor(x[2]*10000)*0.01, math.floor(x[3]*10000)*0.01 + local hsv_rgb = vectors.hsvToRGB(x) + local hsv_r, hsv_g, hsv_b = math.floor(hsv_rgb[1]*255), math.floor(hsv_rgb[2]*255), math.floor(hsv_rgb[3]*255) + str = str .. (',"\n[RGB]:\n Color: ",{"text":"Lorem_Ipsum █ ⏹⏺◆\n","color":"#%06X"}," RGB: ",{"text":"⏺ %d","color":"#%02X0000"},", ",{"text":"⏺ %d","color":"#00%02X00"},", ",{"text":"⏺ %d\n","color":"#0000%02X"}," HSV: ",{"text":"⏺ %d°","color":"#%06X"},", ",{"text":"⏺ %s%%","color":"#%06X"},", ",{"text":"⏺ %s%%\n","color":"#%06X"},"[HSV]:\n Color: ",{"text":"Lorem_Ipsum █ ⏹⏺◆\n","color":"#%06X"}," HSV: ",{"text":"⏺ %d°","color":"#%06X"},", ",{"text":"⏺ %s%%","color":"#%06X"},", ",{"text":"⏺ %s%%\n","color":"#%06X"}," RGB: ",{"text":"⏺ %d","color":"#%02X0000"},", ",{"text":"⏺ %d","color":"#00%02X00"},", ",{"text":"⏺ %d\n","color":"#0000%02X"}'):format( + vectors.rgbToINT(x), + rgb_r, rgb_r, + rgb_g, rgb_g, + rgb_b, rgb_b, + rgb_h, vectors.rgbToINT(vectors.hsvToRGB(vectors.of{rgb_hsv[1], 1, 1})), + tostring(rgb_s), vectors.rgbToINT(vectors.hsvToRGB(vectors.of{0, rgb_hsv[2], 1})), + tostring(rgb_v), vectors.rgbToINT(vectors.hsvToRGB(vectors.of{0, 0, rgb_hsv[3]})), + + vectors.rgbToINT(vectors.hsvToRGB(x)), + hsv_h, vectors.rgbToINT(vectors.hsvToRGB(vectors.of{x[1], 1, 1})), + tostring(hsv_s), vectors.rgbToINT(vectors.hsvToRGB(vectors.of{0, x[2], 1})), + tostring(hsv_v), vectors.rgbToINT(vectors.hsvToRGB(vectors.of{0, 0, x[3]})), + hsv_r, hsv_r, + hsv_g, hsv_g, + hsv_b, hsv_b + ) + end + + return ('{"action":"show_text","value":[%s,"\nMethods: "%s]]}'):format( + str, + JSON.stringify.vectorMethods() + ) + end, + other = function(x) + return ('{"action":"show_text","value":[{"text":"%s\n","color":"%s"},{"text":"%s","color":"%s"}]}'):format( + type(x):gsub("^.", string.upper), rto.type, + tostring(x):gsub("\\\"", "\\%1"), rto.default + ) + end + } + end + + local rotbl = { + __metatable = false, + __newindex = function() error("attempt to modify read-only table") end + } + + REPL = { + currentcommand = "", + stringify = JSON.stringify, + theme = repl_theme, + bound = false, + key = keybind.newKey("[REPL] Bind to Chat", "GRAVE_ACCENT"), + keyWP = false, + log = function(x, detail, inHover, options) + options = type(options) == "table" and options or {} + log(('[{"text":"","italic":false}%s]'):format( + JSON.stringify.any(x, detail, inHover, { + indent = options.indent, length = options.length, max = options.max + }) + ), true) + end, + ---@type {boolean: number, number: string, string: table, table: Vector, Vector: userdata, userdata: boolean} + testtable = setmetatable({ + [true] = 123.456, + [123.456] = "\abcxyz", + ["qwer\ty"] = setmetatable({"hello", "world", setmetatable({"!"}, rotbl)}, rotbl), + [setmetatable({"foo","bar","baz",yalike="jazz?"}, rotbl)] = vectors.of{1,2,3,4,5,math.sqrt(2)}, + [vectors.of{1,2,3,4,5,math.sqrt(2)}] = item_stack.createItem("minecraft:stick")["figura$item_stack"], + [item_stack.createItem("minecraft:stone")["figura$item_stack"]] = false + }, rotbl), + RegisterStringifier = function(name, stringify) + + end + } + local REPL = REPL + local REPLSuperActions = { + fixstringmt = { + func = function() + local t = {} + for k,f in pairs(string) do + t[k] = f + end + getmetatable("").__index = t + log("Set string metatable index to " .. tostring(string)) + end, + desc = "Repairs the string metatable.", + help = "Repairs the string metatable.\n" .. + "This is useful if you somehow broke string methods.\n" .. + "The string metatable is required to be functional for the REPL to run.\n" .. + "Usage:\n" .. + " $$#fixstringmt" + }, + error = { + func = function() + error("forced critical REPL error.") + end, + desc = "Force a critical error in the REPL.", + help = "Force a critical error in the REPL.\n" .. + "Used to emulate a Lua error in the REPL itself instead of an error with REPL input.\n" .. + "Usage:\n" .. + " $$#error" + }, + avatarerror = { + func = function(yes) + if yes == "yes" then + return "\0\9\0\70\79\82\67\69\0\9\0" + else + log("Please use \"$$#avatarerror yes\" to confirm.") + end + end, + desc = "Force your avatar to error.", + help = "Force your avatar to error.\n" .. + "The only way to reverse this action is to reload the avatar.\n" .. + "Usage:\n" .. + " $$#avatarerror - Does nothing.\n" .. + " $$#avatarerror yes - Causes an avatar error." + }, + mlcancel = { + func = function() + if REPL.currentcommand == "" then + log("There is no current Multi-line input!") + else + REPL.currentcommand = "" + end + end, + desc = "Cancels the current multi-line input.", + help = "Cancels the current multi-line input.\n" .. + "Useful if you want to cancel an entire chunk of multi-line Lua without causing issues.\n" .. + "Usage:\n" .. + " $$#mlcancel" + }, + mlback = { + func = function() + local lastline = REPL.currentcommand:find("[^\n]*\n$") + if lastline then + REPL.currentcommand = REPL.currentcommand:sub(1, lastline-1) + else + log("There is no current Multi-line input!") + end + end, + desc = "Deletes the last line of a multi-line input.", + help = "Deletes the last line of a multi-line input.\n" .. + "Useful if you make an error and you want to try again.\n" .. + "Usage:\n" .. + " $$#mlback" + }, + mlrun = { + func = function() + if REPL.currentcommand == "" then + log("There is no current Multi-line input!") + else + REPL() + end + end, + desc = "Run the current Multi-line input as is.", + help = "Run the current Multi-line input as is.\n" .. + "Useful if you accidentally start a new line instead of running the input.\n" .. + "Usage:\n" .. + " $$#mlrun" + }, + mlprint = { + func = function() + if REPL.currentcommand == "" then + log("There is no current Multi-line input!") + else + log(('[{"text":"Current input:\n","italic":false},{"text":"%s","color":"%s"}]'):format( + REPL.currentcommand:gsub("([\\\"])", "\\%1"), + rtr.user_input + ), true) + end + end, + desc = "Prints the current Multi-line input to chat.", + help = "Prints the current Multi-line input to chat.\n" .. + "Useful if you forgot where you were in your multi-line input.\n" .. + "Usage:\n" .. + " $$#mlprint" + }, + set = { + func = function(args) + local cat, set, val = args:match("^([^.]*)%.?(%S*) ?(.*)$") + if cat == "" then + local options = {} + for k in pairs(repl_theme) do + if k ~= "" then options[#options+1] = k end + end + table.sort(options) + local strs = {} + for _,k in ipairs(options) do + strs[#strs+1] = k + end + log("Categories:\n" .. table.concat(strs, ", ")) + elseif not repl_theme[cat] then + log(("Theme category [%s] not found.\nUse \"$$#set\" to list all categories."):format(cat)) + elseif set == "" then + local tcat = repl_theme[cat] + local options = {} + for k in pairs(tcat) do + if k ~= "" then options[#options+1] = k end + end + table.sort(options) + local strs = {} + for _,k in ipairs(options) do + local v = tcat[k] + strs[#strs+1] = ("[%s] - %s"):format( + k, + (type(v) == "string" and not v:match("^#%x%x%x%x%x%x$")) + and ('"' .. tostring(v):gsub("([\\\"])", "\\%1") .. '"') + or tostring(v) + ) + end + log("Settings for category:\n[" .. cat .. "]:\n " .. table.concat(strs, "\n ")) + elseif repl_theme[cat][set] == nil then + log(("Theme setting [%s.%s] not found.\nUse \"$$#set %s\" to list all settings in this category."):format( + cat, set, + cat + )) + elseif val == "" then + local tset = repl_theme[cat][set] + local tsett = type(tset) + log(("Value for setting:\n[%s.%s]:\n %s"):format( + cat, set, + (tsett == "string" and not tset:match("^#%x%x%x%x%x%x$")) + and ('"' .. tostring(tset):gsub("([\\\"])", "\\%1") .. '"') + or (tsett == "number" and math.abs(tset) == math.huge) + and (tset < 0 and "-Infinity" or "Infinity") + or tostring(tset) + )) + else + ---@type string|number|boolean + local value + if val:match("^\".+\"$") then + value = val:sub(2,-2) + elseif val:match("^#%x%x%x%x%x%x$") then + value = val + elseif tonumber(val) then + value = tonumber(val) + elseif val == "true" or val == "false" then + value = val == "true" + elseif val:match("^%-?[Ii]nfinity$") or val:match("^%-?[Ii]nf$") then + local m = val:sub(1,1) == "-" + value = m and -math.huge or math.huge + else + log("Invalid value. Please do \"$$#help set\" to see what values can be used.") + return + end + repl_theme[cat][set] = value + end + end, + desc = "Quickly set REPL theme settings.", + help = "Quickly set REPL theme settings.\n" .. + "Please make sure you are using sane values. The resulting value is not checked.\n" .. + "Usage:\n" .. + " $$#set - View all categories.\n" .. + " $$#set - View all settings in the category.\n" .. + " $$#set - View the current value for this setting.\n" .. + " $$#set - Sets the setting to the given value.\n" .. + " can be:\n" .. + " {string} (\"string\"),\n" .. + " {number} (123.45),\n" .. + " {boolean} (true/false)" + } + } + + local RSABlCSt, RSABlCStT, RSABlCStH = false, "", "" if loadSecrets then + --[[ + I see you are poking around... + + Everything in this block is part of the "REPL Secret" and is for fun. + If you ruin the fun and cheat to view these then I will be disappointed in you :( + + If you *really* want a hint to one of them, mention GrandpaScout with the message + "I need a REPL moment." in Blancworks' general chat. + You will get a reply as soon as the message is recieved. The reply will have a warning and + will be spoilered to avoid spoiling it for others. + ]]-- + + local function RSASt2Sc(a) + ---@diagnostic disable-next-line: deprecated + return loadstring("return ".. loadstring(([[return(%s):gsub("(%%d%%d%%d)",function(a)return _G["\115\116\114\105\110\103"]["\99\104\97\114"](_G["\116\111\110\117\109\98\101\114"](a))end)]]):format(a))())() + end + RSABlCSt = RSASt2Sc[[(0 ..0x1EF6BAD164A9 ..0x9EB5E76D48F ..0x3BE5BEF1E60 ..0x931D9C4F0FF ..0x24F8D26F541A ..0x3DF25A8612EC ..0x98F37246B83 ..0x6C7D92)]] + RSABlCStT = RSASt2Sc[[(0 ..0x1EFD07B8A344 ..0x93226C12A77 ..0x40AF269AE82A ..0x5A25443C9646 ..0xA76E7ABBE7B ..0x4)]] + RSABlCStH = RSASt2Sc[[(0 ..0x319C4710DF4 ..0x4998C482275A ..0x630D54ECBA1 ..0x12A095FD6C98 ..0xBBA2)]] + + local a = RSASt2Sc[[( + 0x0B3231CBD021 ..0x526905BAC99C ..0x00E6C5CD67E7 ..0x0921A115728F ..0x095F167E326F + ..0x256F8B738488 ..0x1EF9C105B2BE ..0x0AA6D8708B36 ..0x37FFC3C02FD8 ..0x1F0351679E0F + ..0x0A5F0FF3BF8B ..0x2E1CAD3F0564 ..0x3C13A2D6FE82 ..0x098F6CC348DA ..0x2E601D23269C + ..0x08D4F9787560 ..0x2DD4705871B5 ..0x0F8DA57AE936 ..0x091955403431 ..0x12A095FD6C98 + ..0x045F43E24636 ..0x496349555AA0 ..0x085F29620443 ..0x2539E689E835 ..0x00000104F145 + )]] + REPLSuperActions[RSASt2Sc[[(0 ..0x1F0315CCDFC6 ..0x643B6EA)]]] = a + REPLSuperActions[RSASt2Sc[[(0 ..0x1F0315BDB4FD ..0x1D8CA)]]] = a + REPLSuperActions[RSASt2Sc[[(0 ..0x1F047A97F46A ..0xAA6C6738BDF ..0xFC2)]]] = a + + REPLSuperActions[RSASt2Sc[[(0 ..0x1F047AD4F98C ..0x1B5A2)]]] = RSASt2Sc[[( + 0x0B3231CBD021 ..0x526905BAC99C ..0x00E6C5CD67E7 ..0x0921A115728F ..0x095F167E326F + ..0x256F8B738488 ..0x0318F9B3C707 ..0x096309D1B6DE ..0x1D2BD5A43A75 ..0x0B01FF8B9727 + ..0x03AACC21F4F4 ..0x09D52E028E0C ..0x24B09E71EFA9 ..0x0102C4CE21EB ..0x24B2D7A235E2 + ..0x04A4A5F8F2EC ..0x03AB436705C1 ..0x09D5049A462D ..0x075E6A9EBC93 ..0x09328033F89B + ..0x058F8DC725F1 ..0x09322728DDB9 ..0x0967AEE45498 ..0x045FBAF1B627 ..0x1BE76712F45C + ..0x085F29620449 ..0x12A073723033 ..0x0EA7DC39C645 + )]] + + REPLSuperActions[RSASt2Sc[[(0 ..0x1F0351C34AC9 ..0x18AAA)]]] = RSASt2Sc[[( + 0x0B3231CBD021 ..0x526905BAC99C ..0x00E6C5CD67E7 ..0x0921A115728F ..0x095F167E326F + ..0x256F8B738488 ..0x0318F9B3C76A ..0x2DE00D6584B4 ..0x08D4DB95B5F6 ..0x401553900D14 + ..0x09039C3D3DE7 ..0x24B085F6127E ..0x045EBABED2C9 ..0x0669EDFBF082 ..0x098F6CC348DA + ..0x2E601D23269C ..0x08D4F9787560 ..0x2DD4705871B5 ..0x0F8DA57AE936 ..0x091955403431 + ..0x12A095FD6C98 ..0x045F43E24636 ..0x496349555AA0 ..0x085F29620443 ..0x2539E689E835 + ..0x00000104F145 + )]] + + a = RSASt2Sc[[( + 0x0B3231CBD021 ..0x526905BAC99C ..0x00E6C5CD67E7 ..0x0921A115728F ..0x095F167E326F + ..0x256F8B738488 ..0x1EF9C1060C97 ..0x0AA4DDBC283F ..0x49ADE03DDEFC ..0x58510B785A74 + ..0x0A192ADEE53F ..0x06789D11CEAD ..0x09309D5D23C3 ..0x492DA202AD14 ..0x09039C3D3DE7 + ..0x24B085F6127E ..0x04BC4DDD3629 ..0x03AFE7425482 ..0x098F6CC348DA ..0x2E601D23269C + ..0x08D4F9787560 ..0x2DD4705871B5 ..0x0F8DA57AE936 ..0x091955403431 ..0x12A095FD6C98 + ..0x045F43E24636 ..0x496349555AA0 ..0x085F29620443 ..0x2539E689E835 ..0x00000104F145 + )]] + REPLSuperActions[RSASt2Sc[[(0 ..0x1F065843EBC8 ..0xA77F9EE04FB ..0x16BA79CB2)]]] = a + REPLSuperActions[RSASt2Sc[[(0 ..0x1F065843EBC8 ..0xA77F9EE04FB ..0x58C86BD53DA)]]] = a + + a = RSASt2Sc[[( + (0x0B3231CBD021 ..0x526905BAC99C ..0x00E6C5CD67E7 ..0x0921A115728F ..0x095F167E326F + ..0x256F8B738488 ..0x004F4C2B94B9 ..0x0927B29E72B8 ..0x0A8F4258B5A2 ..0x40B5F99E5396 + ..0x1D359CF9FCA8 ..0x093227415F8F ..0x03BAD88F4BD9 ..0x0960E1E54627 ..0x1312B7069280 + ..0x3C1FFDA52053 ..0x0AD545908417 ..0x0493A07AE0C5 ..0x09EC94A89ECF ..0x37ABA370E8B7 + ..0x0CC31A671095 ..0x0A6116DBD22A ..0x2E79E2C4ADF9 ..0x09294F8018A1 ..0x0ABDC101B39E + ..0x0103D8B25B08 ..0x09D528777C0B ..0x0100963B66CA ..0x0931D9C4D60B ..0x01E933FB41AC + ..0x09309D5D2DE7 ..0x132C54246601 ..0x0A18E4AE4540 ..0x098F0779E887 ..0x02C1F75E606D + ..0x001927372A29 ..0x091AA8A55EE7 ..0x01EAD46133EC ..0x098F49090CEA ..0x2E77941DDCEF + ..0x0E94C449A790 ..0x00FE054A7CF9 ..0x092DC0A2F420 ..0x0A1B259F98E7 ..0x40B87F163209 + ..0x0101775D7E7B ..0x01D9210E2115 ..0x09ECAC09112A ..0x01020063F0A0 ..0x094975AAFEC9 + ..0x40A5E123574B ..0x0DABEFF0F2C9 ..0x098F49090CEB ..0x378437C7CA84 ..0x1D32D14DE7F4 + ..0x0932450EA80B ..0x058ED5E5D4A5 ..0x09D5168FBE8B ..0x0A26A1E281C5 ..0x015E45C6D07B + ..0x01D920B2B6B1 ..0x0960827C8BAF ..0x131E5BDCBFE0 ..0x09039C404CB7 ..0x3773F0D38679 + ..0x1320EADB2301 ..0x0A0389363985 ..0x4090E5927D03 ..0x00034460CF56 ..0x09190DE47A4D + ..0x52D421A51444 ..0x1D359CFA0C96 ..0x0960D57C6D86 ..0x04A72F903F46 ..0x098F1F6562B1 + ..0x4010CE147020 ..0x1D2AE766AA55 ..0x093244C6FE4F ..0x131E5BDCBFE1 ..0x0EA3E659D556 + ..0x095EE744A18E ..0x52C5FDDC5883 ..0x0E94C4498850 ..0x0A8F425ECE2F ..0x24ABF6F09BCA + ..0x1D359D63BF30 ..0x001A918D7B19 ..0x091AA8A560E3 ..0x0103617D1188 ..0x093056460A3F + ..0x01EC3AD79B15 ..0x09190DE47D6E ..0x409EB84AD00C ..0x1D220C37D0B1 ..0x09EC4D20890F + ..0x377D43F1357D ..0x0A1BAFEF6754 ..0x0AD4F228E78F ..0x01E8809231D6 ..0x095EE727872B).. + (0x2E6E418DA17A ..0x02EB51AF40D3 ..0x1317634C9DBB ..0x0A1C67B14229 ..0x0A0377C3F9C2 + ..0x2E62A2ADC9C8 ..0x1D3130D88840 ..0x094975AAFECB ..0x0677EA332C5C ..0x098F49090CEB + ..0x378437BCA5DC ..0x078E0E18161B ..0x09FF139C4BCE ..0x03BBA1DA607B ..0x127B495C1D83 + ..0x0CD57F94E666 ..0x0A1B133DC452 ..0x0A0D08F387B0 ..0x08D3346EFC8E ..0x075C131CAD33 + ..0x00F2637C0F00 ..0x008BD13625D9 ..0x091FC3B55529 ..0x0A03DD11CC59 ..0x2DC446968B64 + ..0x1D33FB53BEA1 ..0x0A038936385A ..0x03BAD88F4BD9 ..0x0960E1E54627 ..0x131C0D2E7733 + ..0x00178D128D67 ..0x000255F5A756 ..0x09190D939F79 ..0x40AA7D457155 ..0x0019E1ADB859 + ..0x091FC3B568B1 ..0x09EC2365DCFF ..0x2DC446968B64 ..0x1D3130BA4E39 ..0x0B03EDD8BB91 + ..0x40A828AC8FDB ..0x001785E05BD7 ..0x000255F5A756 ..0x09190DD84A5C ..0x2537AFA5FE41 + ..0x0EA58738B0B0 ..0x09322D31273A ..0x096316ECF856 ..0x1D356225BB30 ..0x0A1B13BDD70B + ..0x52CD20BEFB00 ..0x06A4693D09E0 ..0x2537AFA5FE41 ..0x0EA58738B0B0 ..0x09322D31273A + ..0x096316ECF856 ..0x1D3561D944F6 ..0x09190DDFE92A ..0x01014DEDE7F4 ..0x098F43101EAA + ..0x03BADD178B50 ..0x098F49090CEB ..0x0A26A1E281C5 ..0x015E45C6D07B ..0x127B6395D472 + ..0x1D34AE613548 ..0x09D4EC5CA786 ..0x2563BE16E3B5 ..0x1320EBCF46B8 ..0x09EC1D6E7557 + ..0x133353413073 ..0x0CD669798C41 ..0x0AA684E45139 ..0x01EB47B5B174 ..0x0977CA8104CA + ..0x0A1B026CD2B2 ..0x02EBC2E5CAEF ..0x057C75B85093 ..0x09305656D12A ..0x0962F7566B8B + ..0x092F62683BCA ..0x09BDF7580BF6 ..0x0A220222F4C4 ..0x1D312C325135 ..0x0A8F89E55DAB + ..0x01EBC373EE4B ..0x09309DB8C07B ..0x127B6395D472 ..0x1D3130401531 ..0x010061AC794B + ..0x092F98D37A37 ..0x091AA9227E2F ..0x37948BDC2E71 ..0x0A18E4AE3988 ..0x0930560A8779 + ..0x40AA7D52B847 ..0x0CD491948E33 ..0x09323F1BEF3F ..0x24C7E2BC9020 ..0x1D3130D88840).. + (0x0A1ACBB738B7 ..0x0A28FBE66922 ..0x1D2F8ED6CC54 ..0x0109A7234680 ..0x06607895CF9C + ..0x24ABD7F58B7C ..0x2D85A64E0844 ..0x093256E7447E ..0x075FCD15984F ..0x09EC70D924FB + ..0x0A1D2DE523CB ..0x092F98D34B56 ..0x0B01FF8B997F ..0x37A284216390 ..0x3C1FFDA52053 + ..0x0AD545908417 ..0x0493A089FBFE ..0x09321B4DFF2A ..0x0A22004EA97D ..0x0A1BAFEFBD47 + ..0x0A60C358BDA2 ..0x1B93AF0E6BA1 ..0x0EA58738B086 ..0x098F1F6562B1 ..0x3FF4E7A7E858 + ..0x006B5109DA79 ..0x00EA58BB390F ..0x52BCE2B9B468 ..0x004AC87A57F3 ..0x091FC898EB7F + ..0x0A60B77DC0FA ..0x1B982F2B39FF ..0x0102A1806FEB ..0x24E858C57E42 ..0x05EAF5D4245E + ..0x36E11A831A3B ..0x0176CA3DB58D ..0x083767D2F551 ..0x09D5403840F7 ..0x0839BF540AC5 + ..0x00178684D936 ..0x091955403431 ..0x12A095FD6C98 ..0x045F43E24636 ..0x496349555AA0 + ..0x085F29620443 ..0x2539E689E835 ..0x00000104F145) + )]] + REPLSuperActions[RSASt2Sc[[(0 ..0x1F0403DC5B0D ..0x6CCFB8A)]]] = a + REPLSuperActions[RSASt2Sc[[(0 ..0x31A0062D5E7 ..0x6C4ACA)]]] = a + REPLSuperActions[RSASt2Sc[[(0 ..0x4F640E638B ..0x92F62683BCA ..0x662721A)]]] = a + end + REPLSuperActions.help = { + func = function(arg) + local SA = REPLSuperActions[arg] + if SA and not v[RSABlCStH] then + log(string.format('{"text":"Help for [%s]:\n%s\n","italic":false}', + arg == "" and "help" or arg, + SA.help + and string.gsub(SA.help, "([\\\"])", "\\%1") + or string.format("No help found for this SuperAction.\nAssumed usage:\n $$#%s - Run SuperAction", arg) + ), true) + else + log("No SuperAction with that name found.") + end + end, + desc = "Provides help about SuperActions.", + help = "Provides help about SuperActions.\n" .. + "Usage:\n" .. + " $$#help - Get help about the help SuperAction.\n" .. + " $$#help - Get help about the named SuperAction." + } + REPLSuperActions[""] = { + func = function(arg) + local a = arg == RSABlCSt + local topics = {} + for k in pairs(REPLSuperActions) do + topics[#topics+1] = k + end + table.sort(topics) + local strs = {} + for _,k in ipairs(topics) do + v = REPLSuperActions[k] + if not v[RSABlCStH] then + strs[#strs+1] = string.format("[$$#%s]: %s", k, v.desc or "No description provided...") + end + end + log("All SuperActions:\n" .. table.concat(strs, "\n") .. "\n") + if a then + local astrs = {} + for _,k in ipairs(topics) do + if REPLSuperActions[k][RSABlCStH] then + astrs[#astrs+1] = string.format("@ [$$#%s]", k) + end + end + log(RSABlCStT .. table.concat(astrs, "\n") .. "\n") + end + end, + desc = "List all SuperActions.", + --"What? That's not what this SA does!" + --If this were to be typed out in chat, it would look like this "$$#help". + --Therefore, this is actually the help topic for the help SA. + help = "Provides help about SuperActions.\n" .. + "Usage:\n" .. + " $$#help - Get help about the help SuperAction.\n" .. + " $$#help - Get help about the named SuperAction.\n\n" .. + "If you were looking for a list of SuperActions, try \"$$#\"." + } + local REPLmt = setmetatable({ + __newindex = function() + error("The REPL table is immutable to avoid self-destruction of the REPL.") + end, + __call = function(self, cmd) + local str, nl + if cmd ~= nil then + cmd = tostring(cmd) + if string.sub(cmd, 1, 3) == "$$#" then + --Assume the worst, the code in this block should *all* run even if the string metatable is fucked. + local SAcmd, SAarg = string.match(cmd, "^$$#(%S*) ?(.*)$") + SAcmd = string.lower(SAcmd) + if REPLSuperActions[SAcmd] then + log(string.format('{"text":"REPL: Running SuperAction.","color":"%s","italic":false}', rtr.notice), true) + local ret = REPLSuperActions[SAcmd].func(SAarg) + if ret == "\0\9\0\70\79\82\67\69\0\9\0" then + return "\0\9\0\70\79\82\67\69\0\9\0" + end + else + log(string.format('{"text":"REPL: SuperAction not found!\nUse $$# to list all valid SuperActions.","color":"%s","italic":false}', rtr.error), true) + end + return + end + str, nl = cmd:match("^(.-)(;?)$") + if not str then error "Command error." end + if #REPL.currentcommand == 0 and str:sub(1,1) == "/" then + log(('{"text":"REPL: Ignoring Minecraft command.","color":"%s","italic":false}'):format(rtr.notice), true) + chat.setFiguraCommandPrefix() + chat.sendMessage(str) + chat.setFiguraCommandPrefix("") + return + end + REPL.currentcommand = REPL.currentcommand .. str .. "\n" + else + str = "" + end + if nl ~= ";" then + chat.setFiguraCommandPrefix() + local ccmd = REPL.currentcommand:sub(1, -2) + REPL.currentcommand = "" + local f = loadstring("return " .. ccmd) + if type(f) == "function" then + log(('[{"text":"INPUT:\n","color":"%s","italic":false},{"text":"return ","color":"%s"},{"text":"%s\n","color":"%s"}]'):format( + rtr.input, + rtr.repl_return, + ccmd:gsub("([\\\"])", "\\%1"), rtr.user_input + ), true) + else + f = loadstring(ccmd) + if type(f) == "function" then + log(('[{"text":"INPUT:\n","color":"%s","italic":false},{"text":"%s\n","color":"%s"}]'):format( + rtr.input, + ccmd:gsub("([\\\"])", "\\%1"), rtr.user_input + ), true) + else + log(('{"text":"REPL: Compile Error!\n%s","color":"%s","italic":false}'):format( + f:gsub("\t", " "):gsub("([\\\"])", "\\%1"), rtr.error + ), true) + chat.setFiguraCommandPrefix("") + return + end + end + local r = {pcall(f)} + if not r[1] then + log(('{"text":"REPL: Runtime Error!\n%s","color":"%s","italic":false}'):format( + r[2]:gsub("\t", " "):gsub("([\\\"])", "\\%1"):gsub("§.", ""), rtr.error + ), true) + chat.setFiguraCommandPrefix("") + return + end + table.remove(r, 1) + local _H = {} + H[#H+1] = _H + local rh = 0 + for i in pairs(r) do if i > rh then rh = i end end + for i=1,rh do + local v = r[i] + _H[i] = v + r[i] = JSON.stringify.any(v, true, false, { + indent = rtt.max_indent < 0 and rtt.max_indent or nil, + length = type(v) == "string" and rts.max_size or rtt.max_length + }) + end + if rh == 0 then + r[1] = ('%s,{"text":" (no value?)","color":"%s"}'):format( + JSON.stringify["nil"](), + rtx.no_value + ) + end + log(('[{"text":"RETURNS:\n","color":"%s","italic":false}%s,"\n"]'):format( + rtr.returns, + table.concat(r, ',"\n"') + ), true) + chat.setFiguraCommandPrefix("") + end + end + }, { + __newindex = function() + error("The REPL metatable is immutable to avoid self-destruction of the REPL.") + end, + __metatable = false + }) + + --Store pointer to the Environment. + --[[ O[1] ]] O[_ENV] = true + + --Store pointers to REPL values. + --[[ O[2] ]] O[REPL] = true + --[[ O[3] ]] O[REPL.key] = true + --[[ O[4] ]] O[REPL.log] = true + --[[ O[5] ]] O[REPL.stringify] = true + --[[ O[6] ]] O[REPL.theme] = true + + --Store pointer to REPL metatable. + --[[ O[7] ]] O[REPLmt] = true + + --Store pointers to O values. + --[[ O[8] ]] O[O] = true + --[[ O[9] ]] O[O.N] = true + --[[ O[10] ]] O[O.Nindex] = true + + --Store pointers to instances. + INSTANCE_Biome = biome.getBiome("minecraft:plains", {}) + --[[ O[11] ]] O[INSTANCE_Biome] = true + + INSTANCE_BlockState = block_state.createBlock("minecraft:stone") + --[[ O[12] ]] O[INSTANCE_BlockState] = true + + INSTANCE_ItemStack = item_stack.createItem("minecraft:shield") + --[[ O[13] ]] O[INSTANCE_ItemStack] = true + + INSTANCE_FiguraKeybind = keybind.newKey("[REPL] ", "UNKNOWN") + --[[ O[14] ]] O[INSTANCE_FiguraKeybind] = true + + INSTANCE_RegisteredKeybind = keybind.getRegisteredKeybind("key.jump") + --[[ O[15] ]] O[INSTANCE_RegisteredKeybind] = true + + INSTANCE_Vector = vectors.of{1,2,3,4,5,6} + --[[ O[16] ]] O[INSTANCE_Vector] = true + + setmetatable(REPL, REPLmt) + + onCommand = function(cmd) + if REPL.bound then + local s, e = pcall(REPLmt.__call, nil, cmd) + if not s then + --Again, we have to assume the worst. + log( + string.format( + '{"text":"REPL: Critical REPL error!\n%s","color":"%s","italic":"false"}', + string.gsub(string.gsub(string.gsub(e, "\t", " "), "([\\\"])", "\\%1"), "§.", ""), + rtr.error + ), + true + ) + + if not checkSMT() then + log('{"text":"\nThe string metatable has been tampered with!\nCore REPL functions cannot run without a valid string metatable!\nYou can use \\"$$#fixstringmt\\" to attempt to fix the issue.","color":"dark_red","italic":false}', true) + end + chat.setFiguraCommandPrefix("") + elseif e == "\0\9\0\70\79\82\67\69\0\9\0" then + error("FORCED AVATAR ERROR.\nRELOAD AVATAR TO REGAIN CONTROL.\n") + end + end + end + + function tick() + local REPLkeyIP = REPL.key.isPressed() + if REPLkeyIP and not REPL.keyWP then + if REPL.bound then + REPL.bound = false + chat.setFiguraCommandPrefix() + log(string.format('{"text":"REPL: Unbound from chat.","color":"%s","italic":false}', rtr.notice), true) + else + REPL.bound = true + chat.setFiguraCommandPrefix("") + log(string.format('{"text":"REPL: Bound to chat.","color":"%s","italic":false}', rtr.notice), true) + end + end + REPL.keyWP = REPLkeyIP + end +end +-- }}} +