Desolath

Untitled

Sep 29th, 2025
7
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 22.08 KB | None | 0 0
  1. --// init
  2. local Settings = {
  3. return_values = true,
  4. max_table_size = 3,
  5. IncludeFunctionEnv = false,
  6. decode_bytes = true, -- converts stuff like \110 to 'n'
  7. table_display = 'maximized' --[[
  8. maximized:
  9. {
  10. [1] = 1,
  11. [2] = 2,
  12. [3] = 3,
  13. ...
  14. }
  15. minimized:
  16. { [1] = 1, [2] = 2, [3] = 3, ... }
  17. ]]
  18. }
  19.  
  20. type userdata = {}
  21. type _function = (...any) -> (...any)
  22.  
  23. function GetFullName(instance)
  24. local p = instance
  25. local lo = {}
  26. while (p ~= game and p.Parent ~= nil) do
  27. table.insert(lo, p)
  28. p = p.Parent
  29. end
  30. local fullName
  31. if #lo == 0 then
  32. return "nil --[[ PARENTED TO NIL OR DESTROYED ]]"
  33. end
  34. if lo[#lo].ClassName ~= "Workspace" then
  35. fullName = 'game:GetService("' .. lo[#lo].ClassName .. '")'
  36. else
  37. fullName = "workspace"
  38. end
  39. for i = #lo - 1, 1, -1 do
  40. fullName = fullName .. ':FindFirstChild("' .. lo[i].Name .. '")'
  41. end
  42. return fullName
  43. end
  44.  
  45. local function rawlength(t)
  46. local count = 0
  47. for _, _ in next, t do count += 1 end
  48. return count
  49. end
  50. local function move(t1, fromt1, tot1, copyintot2, t2)
  51. local result = {}
  52. local count = 0
  53.  
  54. for k, v in pairs(t1) do
  55. count = count + 1
  56. if count > tot1 then
  57. break
  58. end
  59. if count >= fromt1 then
  60. result[k] = v
  61. end
  62. end
  63.  
  64. local insertionIndex = copyintot2
  65. for k, v in pairs(result) do
  66. t2[k] = v
  67. end
  68. return t2
  69. end
  70.  
  71. local Metatable = {
  72. --[[
  73. A list of metamethod emulators used to call individual
  74. metamethods efficiently.
  75. ]]
  76. metamethods = {
  77. __index = function(self, key)
  78. return self[key]
  79. end,
  80. __newindex = function(self, key, value)
  81. self[key] = value
  82. end,
  83. __call = function(self, ...)
  84. return self(...)
  85. end,
  86. __concat = function(self, b)
  87. return self..b
  88. end,
  89. __add = function(self, b)
  90. return self + b
  91. end,
  92. __sub = function(self, b)
  93. return self - b
  94. end,
  95. __mul = function(self, b)
  96. return self * b
  97. end,
  98. __div = function(self, b)
  99. return self / b
  100. end,
  101. __idiv = function(self, b)
  102. return self // b
  103. end,
  104. __mod = function(self, b)
  105. return self % b
  106. end,
  107. __pow = function(self, b)
  108. return self ^ b
  109. end,
  110. __tostring = function(self)
  111. return tostring(self)
  112. end,
  113. __eq = function(self, b)
  114. return self == b
  115. end,
  116. __lt = function(self, b)
  117. return self < b
  118. end,
  119. __le = function(self, b)
  120. return self <= b
  121. end,
  122. __len = function(self)
  123. return #self
  124. end,
  125. __iter = function(self)
  126. return next, self
  127. end,
  128. __namecall = function(self, ...)
  129. return self:_(...)
  130. end,
  131. __metatable = function(self)
  132. return getmetatable(self)
  133. end,
  134. }
  135. }
  136.  
  137. --// methods
  138.  
  139. --[[
  140. Interceptive hook.
  141.  
  142. Hooks `obj`'s metamethod `metamethod`
  143. ]]
  144. function Metatable.get_L_closure(metamethod: string, obj: {any} | userdata)
  145. local hooked
  146. local metamethod_emulator = Metatable.metamethods[metamethod]
  147.  
  148. xpcall(function()
  149. metamethod_emulator(obj)
  150. end, function()
  151. hooked = debug.info(2, "f")
  152. end)
  153.  
  154. return hooked
  155. end
  156.  
  157. --[[
  158. Interceptive hook.
  159.  
  160. Attempts to scan for all available metamethods
  161. ]]
  162. function Metatable.get_all_L_closures(obj: {any} | userdata)
  163. local metamethods = {}
  164. local innacurate = {}
  165.  
  166. for method, _ in Metatable.metamethods do
  167. local metamethod, accurate = Metatable.get_L_closure(method, obj)
  168. metamethods[method] = metamethod
  169. end
  170.  
  171. return metamethods
  172. end
  173.  
  174. --[[
  175. Non-recursive hook.
  176.  
  177. Calls `f` when a metamethod of `t` gets fired
  178. ]]
  179. function Metatable.metahook(t: any, f: _function)
  180. local metahook = {
  181. __metatable = getmetatable(t) or "The metatable is locked"
  182. }
  183.  
  184. for metamethod, value in Metatable.metamethods do
  185. metahook[metamethod] = function(self, ...)
  186. f()
  187.  
  188. return Metatable.metahook({}, f)
  189. end
  190. end
  191.  
  192. return setmetatable({}, metahook)
  193. end
  194.  
  195. --// Localization
  196.  
  197. local setmetatable = setmetatable
  198. local pcall = pcall
  199. local table = table.clone(table)
  200. local debug = debug
  201. local string = string
  202. local setfenv = setfenv
  203. local getfenv = getfenv
  204.  
  205. local nonluaglobals = {}
  206. local libs = {
  207. coroutine = coroutine,
  208. math = math,
  209. buffer = buffer,
  210. table = table,
  211. string = string,
  212. os = os,
  213. utf8 = utf8,
  214. bit32 = bit32,
  215. debug = debug,
  216. task = task
  217. }
  218.  
  219. for libname, libvalue in next, libs do
  220. for funcname, _ in next, libvalue do
  221. nonluaglobals[funcname] = string.format('%s.%s', libname, funcname)
  222. end
  223. end
  224.  
  225. local SelectedNum = 2147483647 ^ 2
  226. local SelectedStuff = {}
  227.  
  228. table.rawlength = function(t)
  229. local r = 0
  230. for _, _ in next, t do
  231. r = r + 1
  232. end
  233. return r
  234. end
  235.  
  236. table.concat = function(t, sep)
  237. sep = sep or ''
  238. local result = ''
  239. local count = 1
  240. local length = table.rawlength(t)
  241.  
  242. for _, v in next, t do
  243. result = result .. tostring(v)
  244. if count ~= length then
  245. result = result .. sep
  246. end
  247. count = count + 1
  248. end
  249.  
  250. return result
  251. end
  252.  
  253. local noreturnvalue={'print','warn','error','task.spawn','assert','delay','task.delay','printidentity','spawn','collectgarbage','debug.profilebegin','debug.profileend','debug.resetmemorycategory','debug.dumpcodesize','math.randomseed','table.clear','table.foreach','table.foreachi','table.insert','table.sort','task.synchronize','task.desynchronize','task.cancel','buffer.writei8','buffer.writeu8','buffer.writei16','buffer.writeu16','buffer.writei32','buffer.writeu32','buffer.writef32','buffer.writef64','buffer.writestring','buffer.copy','buffer.fill'}
  254.  
  255.  
  256. local stack = {}
  257.  
  258. --// Init
  259.  
  260. local function get_param_num(f)
  261. return debug.info(f, "a")
  262. end
  263.  
  264. local function merge_t(a, b)
  265. local r = {}
  266.  
  267. for i, v in a do r[i] = v end
  268. for i, v in b do r[i] = v end
  269.  
  270. return r
  271. end
  272.  
  273. local lens = {}
  274.  
  275. --// Sandbox
  276. local function Sandbox(f: (...any) -> (...any), upvalues: {any}?, constants: {string}?, protos: {(...any) -> (...any)}?, i: number?, params)
  277. upvalues = upvalues or {}
  278. constants = constants or {}
  279. protos = protos or {}
  280. params = params or {}
  281. i = i or 1
  282.  
  283. local root = {
  284. root = true,
  285. children = {},
  286. stack = {},
  287. params = {},
  288. constants = constants,
  289. upvalues = upvalues,
  290. protos = protos,
  291. pc = 0,
  292. function_info = {debug.info(f, "na")},
  293. f = f,
  294. i = i,
  295. error_message = '',
  296. fenv = getfenv(f)
  297. }
  298.  
  299. local id_i = 0
  300. local last_func
  301.  
  302. local function wrap(parent: {pc: number?, children: {any}, arguments: {any?}?})
  303. local hooks = {}
  304. local t = {}
  305.  
  306. for metamethod in Metatable.metamethods do
  307. local SelectedNum2 = math.random(2 ^ 16, 2 ^ 24)
  308. hooks[metamethod] = function(_, ...)
  309. root.pc += 1
  310.  
  311. local pc = root.pc
  312. local stack = root.stack
  313. local self = {pc = pc, children = {}, parent = parent, arguments = {...}, metamethod = metamethod}
  314.  
  315. SelectedStuff[SelectedNum2] = SelectedNum2 * SelectedNum * pc
  316.  
  317. parent.children[pc] = self
  318.  
  319. if metamethod == "__len" then
  320. return SelectedNum2 * SelectedNum * pc
  321. elseif metamethod == '__tostring' then
  322. return tostring(parent)
  323. end
  324.  
  325. return wrap(self)
  326. end
  327. end
  328.  
  329. if root.pc ~= 0 then
  330. root.stack[t] = root.pc
  331. else
  332. root.stack[t] = id_i
  333. root.params[t] = id_i
  334.  
  335. id_i += 1
  336. end
  337.  
  338. return setmetatable(t, hooks)
  339. end
  340.  
  341. local env = wrap(root)
  342.  
  343. local param_num, vararg = get_param_num(f)
  344.  
  345. for i = 1, param_num do
  346. local arg = wrap(root)
  347.  
  348. table.insert(params, arg)
  349. root.params[arg] = root.i
  350.  
  351. root.i += 1
  352. end
  353.  
  354. if vararg then
  355. local vararg = wrap(root)
  356.  
  357. table.insert(params, vararg)
  358. root.params[vararg] = "..."
  359. end
  360.  
  361. if Settings.return_values then
  362. local original_env = getfenv(f)
  363. local return_value
  364. task.spawn(function()
  365. return_value = {pcall(setfenv(f, env), unpack(params))}
  366. end)
  367. for _ = 1, 100 do
  368. if return_value then break end
  369. task.wait(.1)
  370. end
  371. if not return_value then
  372. warn("ERR_1: Function decompile timeout.")
  373. return
  374. end
  375. if return_value[1] then setfenv(f, original_env) end
  376.  
  377. root.return_value = table.move(return_value, 2, #return_value, 1, {})
  378. root.success = return_value[1]
  379. root.error_message = not root.success and return_value[2]
  380. else
  381. root.success = true
  382. root.return_value = {}
  383. end
  384.  
  385. return root
  386. end
  387.  
  388. local function Clean(a) -- Remove spaces or illegal charcters from the text
  389. return a:match("%w+")
  390. end
  391.  
  392. local libs = {string=string, coroutine=coroutine, buffer=buffer, os=os, task=task, utf8=utf8, math=math, table=table, bit32=bit32, debug=debug}
  393. local format;
  394. local quickaccess = {}
  395.  
  396. function equals(tbl, tbl2) -- Shallow equals for tree.return_value
  397. if type(tbl) ~= 'table' or type(tbl2) ~= 'table' then return tbl == tbl2 end
  398. for i, v in next, tbl do
  399. if tbl2[i] ~= v then return false end
  400. end
  401. return true
  402. end
  403.  
  404. --// Disassembler
  405. local function Disassemble(tree: {any}, tabs: number?)
  406. tabs = tabs or 1
  407. local tab_formatting = (" "):rep(tabs)
  408.  
  409. local stack = tree.stack
  410. local params = tree.params
  411. local upvalues = tree.upvalues
  412. local final_pc = tree.pc
  413. local success = tree.success
  414. local function_info = tree.function_info
  415. local i = tree.i
  416.  
  417. local stack_offset do
  418. stack_offset = (final_pc > 0 and 1) or 0
  419. end
  420.  
  421. local disassembly = {}
  422. local constants = {}
  423. local protos = {}
  424.  
  425. local pc = 0
  426.  
  427. function format(value, tabs2, exclude)
  428. tabs2 = tabs2 or tabs
  429. local type = typeof(value)
  430.  
  431. local s_index = stack[value]
  432. local p_index = params[value]
  433. local uv_index = upvalues[value]
  434.  
  435. if p_index then
  436. if p_index ~= "..." then
  437. return ("_p%d"):format(tonumber(p_index) or 1)
  438. end
  439. return p_index
  440. elseif s_index and tonumber(s_index) then
  441. return ("v%d"):format(tonumber(s_index))
  442. elseif uv_index then
  443. if not upvalues[value] then
  444. disassembly[1] = ("local _uv_%s = v%d[%s]\n"):format(uv_index, uv_index)..(disassembly[1] or "")
  445. else
  446. return ("_p%s"):format(uv_index)
  447. end
  448.  
  449. return ("_uv_%d"):format(uv_index)
  450. elseif not p_index and not s_index and not uv_index and type == 'number' then
  451. return tostring(value)
  452. end
  453.  
  454. if type == exclude then
  455. return nil
  456. end
  457.  
  458. if type == "string" then
  459.  
  460. local s = ""
  461.  
  462. for _, char in {value:byte(1, -1)} do
  463. if char > 126 or char < 32 then
  464. s ..= "\\"..char
  465. else
  466. s ..= string.char(char)
  467. end
  468. end
  469.  
  470. table.insert(constants, value)
  471.  
  472. if Settings.decode_bytes then
  473. s = string.gsub(s, "\\(%d+)", string.char)
  474. end
  475.  
  476. return ('"%s"'):format(s)
  477. elseif type == "table" then
  478. local t = ""
  479. local mt = getmetatable(value)
  480. local count = 0
  481. local total = 0
  482. local a = ' '
  483. local tabf = a:rep(tabs)
  484.  
  485. for _, _ in next, value do
  486. total = total + 1
  487. end
  488.  
  489. for i, v in next, value do
  490. count = count + 1
  491. local betterI = typeof(i) == 'number' and tostring(i) or string.format('"%s"', tostring(i))
  492. local betterV = typeof(v) == 'number' and tostring(v) or format(v, tabs2 + 1)
  493. t ..= ("%s%s[%s] = %s%s"):format(Settings.table_display == 'maximized' and '\n' or '', Settings.table_display == 'maximized' and (a:rep(tabs2) .. ' ') or '', betterI, betterV, count < total and ', ' or '')
  494. end
  495.  
  496. t = ("{%s%s%s%s}"):format(tabf, t, count > 0 and '\n' or '', a:rep(tabs2))
  497.  
  498. if typeof(mt) == 'table' then
  499. local methods = '{'
  500.  
  501. for MethodIndex, _ in Metatable.metamethods do
  502. local rg = rawget(mt, MethodIndex)
  503. if rg then
  504. methods ..= ('%s%s%s = %s;'):format(Settings.table_display == 'maximized' and '\n' or '', tab_formatting .. ' ', MethodIndex, format(rg))
  505. end
  506. end
  507.  
  508. methods = #methods > 1 and methods .. '\n' .. a:rep(tabs + 4) .. '}\n' .. a:rep(tabs + 1) or '{}'
  509.  
  510. t = ('setmetatable(%s, %s)'):format(t, methods)
  511. end
  512.  
  513. return t
  514. elseif type == "function" then
  515. if not table.find(protos, value) and value ~= tree.f then
  516. table.insert(protos, value)
  517.  
  518. local paramcount, isvrg = debug.info(tree.f, 'a')
  519.  
  520. local pars = ''
  521.  
  522. if isvrg then
  523. pars = '...'
  524. else
  525. for i = 1, paramcount do
  526. pars = pars .. '_p' .. tostring(i)
  527. if i ~= paramcount then
  528. pars = pars .. ', '
  529. end
  530. end
  531. end
  532.  
  533. for lib_name, lib_value in next, libs do
  534. for func_name, func_val in next, lib_value do
  535. if func_val == value then
  536. return string.format('%s.%s', lib_name, func_name)
  537. end
  538. end
  539. end
  540.  
  541. local sandbox = Sandbox(value, merge_t(table.clone(params), upvalues), constants, protos, i)
  542. local _disassembly = Disassemble(sandbox, tabs + 1)
  543.  
  544. if sandbox.function_info[1] == "" then
  545. return ("function(%s)\n%s%s\n%send"):format(
  546. pars, tab_formatting, _disassembly, tab_formatting
  547. )
  548. else
  549. disassembly[pc + 1] = ("%slocal function %s(%s) %s\n%send\n"):format(
  550. tab_formatting,
  551. sandbox.function_info[1],
  552. pars,
  553. _disassembly,
  554. tab_formatting
  555. )..(disassembly[pc] or "")
  556.  
  557. pc += 1 + stack_offset
  558.  
  559. return sandbox.function_info[1]
  560. end
  561. elseif value == tree.f then
  562. local func_name = debug.info(value, "n")
  563.  
  564. if func_name == "" then
  565. return "__func__"
  566. else
  567. return func_name
  568. end
  569. else
  570. return ("function() --[[ Unknown proto ]] end")
  571. end
  572. end
  573.  
  574. if type == "userdata" or type == "vector" then
  575. local index = math.random(0, 0xFFF)
  576. stack[value] = index
  577.  
  578. return "newproxy(" .. tostring(getmetatable(value) ~= nil) .. ')'
  579. elseif type == 'Instance' then
  580. return GetFullName(value)
  581. end
  582.  
  583. return tostring(value)
  584. end
  585.  
  586. local function format_tuple(...)
  587. local t = {}
  588.  
  589. local last = 0
  590. for i, index in {...} do
  591. if i - last > 1 then
  592. local void_size = i - last - 1
  593. table.move(table.create(void_size, "nil"), i, void_size, 1, t)
  594. end
  595.  
  596. table.insert(t, format(index))
  597.  
  598. last = i
  599. end
  600.  
  601. return table.concat(t, ", ")
  602. end
  603.  
  604. local function parse(branch, parent)
  605. if math.random(0, 2) == 0 then task.wait() end -- prevent script timeout while maintaining performance
  606.  
  607. pc = branch.pc
  608.  
  609. local metamethod = branch.metamethod
  610. local args = branch.arguments
  611.  
  612. local parent_pc = (parent and parent.pc) or 0
  613. local a, b = args[1], args[2]
  614.  
  615. a = a or '(???)'
  616.  
  617. local global = parent == nil
  618.  
  619. local argCount, isv = debug.info(tree.f, 'a')
  620.  
  621. argCount = isv and math.huge or argCount
  622.  
  623. local push = ("-- unsupported method '%s'"):format(metamethod)
  624.  
  625. local adjusted_pc = (pc - 1) % argCount + 1
  626.  
  627. if metamethod == "__index" then
  628. if global then
  629. push = ("local v%d = %s"):format(pc, a)
  630.  
  631. table.insert(constants, a)
  632.  
  633. stack[pc] = a
  634. else
  635. if not nonluaglobals[a] then
  636. local thing = ''
  637. if Clean(a) == a then
  638. thing = string.format('.%s', tostring(a))
  639. else
  640. thing = string.format("[%s]", tostring(format(a)))
  641. end
  642. push = ("local v%d = %s%s"):format(pc, 'v' .. tostring(parent_pc), thing)
  643. else
  644. local result
  645. if stack[pc-1] then
  646. local lib = stack[pc-1]
  647. result = nonluaglobals[a]:gsub(lib, 'v' .. tostring(pc-1))
  648. end
  649. push = ("local v%d = %s"):format(pc, result or a)
  650. end
  651.  
  652.  
  653. table.insert(constants, a)
  654.  
  655. stack[pc] = Clean(a) == a and '.' .. a or string.format("[%s]", tostring(format(a)))
  656. end
  657.  
  658. elseif metamethod == "__newindex" then
  659. if global then
  660. push = ("local v%d = %s"):format(pc, format(b))
  661.  
  662. table.insert(constants, a)
  663.  
  664. stack[pc] = format(b)
  665. else
  666. push = ("v%d[%s] = %s"):format(parent_pc, format(a), format(b))
  667.  
  668. table.insert(constants, a)
  669.  
  670. stack[pc] = format(b)
  671. end
  672. elseif metamethod == "__call" then
  673. local namecall_info = ""
  674. local namecall_stack = stack[args[1] or -1]
  675. local is_namecall = namecall_stack == parent_pc - 1
  676.  
  677. if is_namecall and (parent and parent.parent and parent.parent.arguments) then
  678. local a = parent.parent.arguments[1] or "(???)"
  679. local b = parent.arguments[1] or "(???)"
  680.  
  681. pcall(function()
  682. namecall_info = ("-- %s.%s(%s)"):format(a, b, format_tuple(unpack(args)))
  683. end)
  684. end
  685. local tpl = format_tuple(unpack(args))
  686. local rgs = tpl:split(',')
  687. local result = ''
  688. for ff, arg in rgs do
  689. local arg2 = arg:gsub(' ', '')
  690. if arg2:sub(1, 2) == '_p' and arg2:sub(3, #arg):match("%d+") == arg2:sub(3, #arg) then
  691. local index = tonumber(arg2:sub(3, #arg))
  692. local nIndex = index
  693. if argCount < index then
  694. nIndex = (index - 1) % argCount + 1
  695. end
  696. arg2 = arg2:gsub(index, nIndex)
  697. end
  698. result = result .. arg2
  699. if ff < #rgs then
  700. result = result .. ', '
  701. end
  702. end
  703. push = ("local v%d = %s(%s)"):format(pc, parent_pc > 0 and 'v' .. tostring(parent_pc) or '_p' .. tostring(adjusted_pc), tpl)
  704. elseif metamethod == '__tostring' then
  705. local thing = ''
  706. if parent_pc > 0 then
  707. thing = thing .. 'v'.. tostring(parent_pc)
  708. else
  709. thing = thing .. '_p'.. tostring(adjusted_pc)
  710. end
  711. push = ("local v%d = tostring(%s)"):format(pc, thing)
  712. else
  713. local only_self = {
  714. __len = "#",
  715. __unm = "-",
  716. }
  717.  
  718. local math = {
  719. __add = "+",
  720. __sub = "-",
  721. __mul = "*",
  722. __div = "/",
  723. __idiv = "//",
  724. __pow = "^",
  725. __eq = "==",
  726. __lt = "<",
  727. __le = "<=",
  728. __mod = "%",
  729. __concat = '..'
  730. }
  731.  
  732. local self_index, math_index = only_self[metamethod], math[metamethod]
  733.  
  734. if self_index then
  735. local thing = self_index
  736. if parent_pc > 0 then
  737. thing = thing .. 'v'.. tostring(parent_pc)
  738. else
  739. thing = thing .. '_p'.. tostring(adjusted_pc)
  740. end
  741. push = ("local v%d = %s"):format(
  742. pc,
  743. lens['v' .. tostring(parent_pc)] or thing
  744. )
  745. table.insert(constants, 'v' .. tostring(pc))
  746. elseif math_index then
  747. push = ("local v%d = v%d %s %s"):format(pc, parent_pc, math_index, format(a))
  748. end
  749. end
  750.  
  751. disassembly[pc + stack_offset] = tab_formatting .. push
  752.  
  753. for _, child in next, branch.children do
  754. parse(child, branch)
  755. end
  756. end
  757.  
  758. for _, child in next, tree.children do
  759. parse(child)
  760. end
  761.  
  762. if success then
  763. local return_value = tree.return_value
  764.  
  765. if final_pc > 0 then
  766. table.insert(disassembly, "")
  767. end
  768.  
  769. if #return_value > 0 then
  770. if type(return_value[1]) == 'table' and rawlength(return_value[1]) < Settings.max_table_size then
  771. table.insert(disassembly, ("%sreturn %s\n"):format(tab_formatting, format_tuple(unpack(return_value))))
  772. elseif type(return_value[1]) == 'table' and rawlength(return_value[1]) > Settings.max_table_size then
  773. table.insert(disassembly, ("%sreturn %s -- Skipped %d elements due to max_table_size.\n"):format(
  774. tab_formatting, format_tuple(
  775. move(return_value[1], 1, Settings.max_table_size, 1, {})
  776. ),
  777. rawlength(return_value[1]) - Settings.max_table_size
  778. )
  779. )
  780. else
  781. table.insert(disassembly, ("%sreturn %s\n"):format(
  782. tab_formatting, format_tuple(unpack(return_value))
  783. )
  784. )
  785. end
  786. end
  787. end
  788.  
  789. disassembly = table.concat(disassembly, "\n")
  790.  
  791. return ((not success and ("%s-- An error occured while decompiling (@pc %d): %s\n"):format(tab_formatting, final_pc, tree.error_message)) or "")..disassembly .. '\n', constants, protos, success
  792. end
  793.  
  794. local function typefind(a, b)
  795. if type(a) ~= 'table' then return a end
  796. local result = {}
  797. for c, d in next, a do
  798. if type(d) == 'table' then
  799. result[c] = typefind(d, b)
  800. elseif type(d) ~= 'table' and type(d) ~= 'function' then
  801. result[c] = d
  802. end
  803. end
  804. return result
  805. end
  806.  
  807. function Decompile(f: (...any) -> (...any), params)
  808. local start = tick()
  809. local Sandboxed = Sandbox(f, {}, {}, {}, 0, params)
  810. local disassembly, constants, protos, _ = Disassemble(Sandboxed)
  811.  
  812. local Output = ''
  813.  
  814. if Settings.IncludeFunctionEnv then
  815. Output = '-- fenv start\n'
  816. for Index, Value in next, Sandboxed.fenv do
  817. if type(Value) ~= 'function' then
  818. local v = typefind(Value, 'function')
  819. Output = Output .. string.format("%s = %s\n", tostring(Index), format(v))
  820. end
  821. end
  822. Output = Output .. '\n\n-- fenv end\n\n'
  823. end
  824.  
  825. if type(f) == 'function' then
  826. local params = {}
  827. local ParamCount, IsVrg = debug.info(f, 'a')
  828. if not IsVrg then
  829. for i = 1, ParamCount do
  830. table.insert(params, '_p' .. tostring(i))
  831. end
  832. else
  833. params = {'...'}
  834. end
  835. local n = debug.info(f, 'n')
  836. Output = Output .. string.format('function %s(%s)\n', n ~= '' and n or '__func__', table.concat(params, ', '))
  837. end
  838.  
  839. Output = Output .. disassembly
  840.  
  841. Output = Output:gsub("(%d+%.*%d*%w*%+*%-*%d*)", function(match) -- The length fixer
  842. local m = tonumber(match)
  843.  
  844. for num, result in SelectedStuff do
  845. if result == m then
  846. local PC = math.round(result/ SelectedNum / num)
  847. local v2 = constants[PC]
  848. local fixedMatch = v2
  849. return fixedMatch
  850. end
  851. end
  852.  
  853.  
  854. return match
  855. end)
  856.  
  857. local values, removed, usage = {}, {}, {}
  858.  
  859. local function getvalue(v)
  860. for var, val in next, values do
  861. if var == v then
  862. return val
  863. end
  864. end
  865. return v
  866. end
  867.  
  868. local function getvar(v)
  869. for var, val in next, values do
  870. if val == v then return var end
  871. end
  872. end
  873.  
  874. Output = Output:gsub('(v%d+)', function(a)
  875. if not usage[a] then usage[a] = 1 else usage[a] = usage[a] + 1 end
  876. end)
  877. Output = Output:gsub("local (v%d+)(%s*)=(%s*)([^%s]+)", function(a, space1, space2, b)
  878. for i, v in next, values do
  879. if v == b then
  880. table.insert(removed, a)
  881. values[a] = getvar(v)
  882. return ""
  883. end
  884. end
  885. usage[a] = usage[a] - 1
  886. values[a] = b
  887. end)
  888.  
  889. Output = Output:gsub('(local%s*v%d+)(%s*=%s*)(%w+)%(', function(v1, v2, var)
  890. local a = var
  891. repeat a = getvalue(a) until not values[a]
  892. if table.find(noreturnvalue, a) then
  893. return var .. '('
  894. else
  895. return v1 .. v2 .. var .. '('
  896. end
  897. end)
  898.  
  899. Output = Output:gsub("(v%d+)%.(%w+)", function(var, index)
  900. if usage[var] == 1 then
  901. table.insert(removed, var)
  902. return string.format('%s.%s', getvalue(var):gsub('v%d+', getvalue), index)
  903. end
  904. end)
  905.  
  906. for _, var in next, removed do
  907. Output = Output:gsub(`local {var}%s*=%s*([^%s]+)`, function(a)
  908. return ""
  909. end)
  910. Output = Output:gsub(`{var}%(`, getvalue(var) .. '(')
  911. Output = Output:gsub(`{var}%.`, getvalue(var) .. '.')
  912. end
  913.  
  914. Output = Output:gsub("\n%s*\n", "\n")
  915.  
  916.  
  917. return string.format("-- Decompiled with Function Dumper (Forked xAPI function decompiler) in about %.14f seconds.\n", tick() - start) .. Output .. 'end'
  918. end
  919.  
  920. return Decompile
Add Comment
Please, Sign In to add comment