• There is NO official Otland's Discord server and NO official Otland's server list. The Otland's Staff does not manage any Discord server or server list. Moderators or administrator of any Discord server or server lists have NO connection to the Otland's Staff. Do not get scammed!

Traverse _G

Codex NG

Recurrent Flamer
Joined
Jul 24, 2015
Messages
2,994
Solutions
12
Reaction score
1,657
I am sure this could be written better...

Ever wanted to know what the server loads when it starts up?
I created a talkaction which creates a log file to traverse the global _G metatable.

Code:
function onSay(player, words, param)
    if param == 'clear' then
        _G = nil
        player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, ' _G has been set to nil.')
        return true
    end
    if _G ~= nil then
        local file = '_G.lua'
        local fileCreated = file
        file = io.open(file, "w+")
        file:write("_G = {\n")
        for x, n in pairs(_G) do
            if type(n) == 'number' or type(n) == 'string' then
                file:write('\t['..x ..'] = '..n.. ",\n")
            elseif type(n) == 'table' then
                file:write("\t["..x.."] = {\n")
                for k, v in pairs(n) do
                    if type(v) == 'number' or type(v) == 'string' then
                        file:write('\t\t['..k ..'] = '..v.. ",\n")
                    elseif type(v) == 'table' then
                        file:write("\t\t["..k.."] = {\n")
                        for kk, vv in pairs(v) do
                            if type(vv) == 'function' then
                                file:write('\t\t\t'..k..'.'..kk.. "() end,\n")
                            elseif type(vv) == 'number' or type(vv) == 'string' then
                                file:write('\t\t\t['..kk..'] = '..vv.. ",\n")
                            elseif type(vv) == 'userdata' then
                                file:write('\t\t\tuserdata '..kk.. ",\n")
                            elseif type(vv) == 'table' then
                                file:write('\t\t\t['..kk.. "] = {\n")
                                for kkk, vvv in pairs(vv) do
                                    if type(vvv) == 'function' then
                                        file:write('\t\t\t\t'..kk..'.'..kkk.. "() end,\n")
                                    elseif type(vvv) == 'number' or type(vvv) == 'string' then
                                        file:write('\t\t\t\t['..kkk..'] = '..vvv.. ",\n")
                                    elseif type(vvv) == 'userdata' then
                                        file:write('\t\t\t\tuserdata '..kkk.. ",\n")
                                    elseif type(vvv) == 'table' then
                                        file:write('\t\t\t\t['..kkk.. "] = {--[[ need to find a new way to access nested]]}\n")
                                    end
                                end
                                file:write("\t\t\t},\n")
                            end
                        end
                        file:write("\t\t},\n")
                    elseif type(v) == 'userdata' then
                        file:write('\t\tuserdata '..k.. ",\n")
                    else
                        file:write('\t\t'..x..'.'..k.. "() end,\n")
                    end
                end
                file:write("\t},\n")
            else
                file:write('\tfunction '..x.. "() end,\n")
            end
        end
        file:write("}\n")
        file:close()
        player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, fileCreated..' created.')
    else
        player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, ' _G is nil.')
    end
    return true
end
 
@Codex NG
Really nice :) It would be cool if you were able to benchmark all your codes and it write log. Then would been cool aswell!
 
@Codex NG
Really nice :) It would be cool if you were able to benchmark all your codes and it write log. Then would been cool aswell!
Maybe you can adapt this to something useful
Code:
-- Benchmarking support.
do
  local function runbenchmark(name, code, count, ob)
    local f = loadstring([[
        local count,ob = ...
        local clock = os.clock
        local start = clock()
        for i=1,count do ]] .. code .. [[ end
        return clock() - start
    ]])
    io.write(f(count, ob), "\t", name, "\n")
  end

  local nameof = {}
  local codeof = {}
  local tests  = {}
  function addbenchmark(name, code, ob)
    nameof[ob] = name
    codeof[ob] = code
    tests[#tests+1] = ob
  end
  function runbenchmarks(count)
    for _,ob in ipairs(tests) do
      runbenchmark(nameof[ob], codeof[ob], count, ob)
    end
  end
end

function makeob1()
  local self = {data = 0}
  function self:test()  self.data = self.data + 1  end
  return self
end
addbenchmark("Standard (solid)", "ob:test()", makeob1())

local ob2mt = {}
ob2mt.__index = ob2mt
function ob2mt:test()  self.data = self.data + 1  end
function makeob2()
  return setmetatable({data = 0}, ob2mt)
end
addbenchmark("Standard (metatable)", "ob:test()", makeob2())

function makeob3()
  local self = {data = 0};
  function self.test()  self.data = self.data + 1 end
  return self
end
addbenchmark("Object using closures (PiL 16.4)", "ob.test()", makeob3())

function makeob4()
  local public = {}
  local data = 0
  function public.test()  data = data + 1 end
  function public.getdata()  return data end
  function public.setdata(d)  data = d end
  return public
end
addbenchmark("Object using closures (noself)", "ob.test()", makeob4())

addbenchmark("Direct Access", "ob.data = ob.data + 1", makeob1())

addbenchmark("Local Variable", "ob = ob + 1", 0)


runbenchmarks(select(1,...) or 100000000)
 
I've no idea what that is, but you may try recursion in this case, no?
If you are referring to the initial post then yes that is possible but I was working in the confines of my system specs and since these nested loops hung the server, imagine what a recursive function would do. :p
 
If you are referring to the initial post then yes that is possible but I was working in the confines of my system specs and since these nested loops hung the server, imagine what a recursive function would do. :p

Hmm, I'm not sure how different it would be, I wouldn't be so fast to say nested loops since LUA is no procedural language, but meh, whatevs, it's fine.
 
Hmm, I'm not sure how different it would be, I wouldn't be so fast to say nested loops since LUA is no procedural language, but meh, whatevs, it's fine.
Every language is procedural, because they are designed around a system that is also procedural, the only computers that have non-procedural programming are quantum computers.
 
Every language is procedural, because they are designed around a system that is also procedural, the only computers that have non-procedural programming are quantum computers.

Well of course machine language is procedural :p, that's not what I mean.

When talking about recursion it is important to notice how languages treat their functions, the sense of having functions as just values help recursion because it offers more flexibility. Though LUA mixes procedural and functional paradigms (even OOP with metatable stuff) I wouldn't be so sure to say nested loops would work faster than recursion in this case.

I hope that was clear enough :)
 
Well of course machine language is procedural :p, that's not what I mean.

When talking about recursion it is important to notice how languages treat their functions, the sense of having functions as just values help recursion because it offers more flexibility. Though LUA mixes procedural and functional paradigms (even OOP with metatable stuff) I wouldn't be so sure to say nested loops would work faster than recursion in this case.

I hope that was clear enough :)
Nested loops offer more control because of the exactness of execution whereas a recursive function does not and can cause an infinite loop.
 
Last I checked lua is not recursive and OOP. Really nice work though.
 
Last I checked lua is not recursive and OOP. Really nice work though.

orly?
Code:
local message = 'Recursions remaining: %d'
local function recurse(i)
    print(message:format(i))
    if i > 0 then
        recurse(i - 1)
    end
end
recurse(20)

And I do agree with @ZooTeam, recursion would be cleaner and easier. Faster who knows, but who really cares, it's a debug function, it would be negligible running once.
 
Last edited:
The global table in Lua (_G) contains itself btw. Which means if you don't exclude it you get an infinite loop.
 
Just store the references and don't iterate over tables that it has already iterated.
 
Nested loops offer more control because of the exactness of execution whereas a recursive function does not and can cause an infinite loop.
You can always limit your function to stop at some point.

The global table in Lua (_G) contains itself btw. Which means if you don't exclude it you get an infinite loop.

This ^ and there are other tables that also have reference to themselves, thats why op has the feeling of infinite loop.


--
I wrote this time ago to generate an autocompletion list for n++
Code:
  local function w(text, parent)
     local f = io.open("list", "a+")
     if(not f) then
       return false
     end

     if (parent ~= nil) and (parent ~= "_G") then
       text = parent .. "." .. text
     end
    
     local o = '\t\t<KeyWord name="' .. text .. '" />'
     f:write(o .. "\n")
     f:close()
   end
  
   local function recursive(arr, parent, level)
     if (level > 3) then
       return
     end
    
     for k, v in pairs(arr) do
       local index = tostring(k)
       print(index)
       if (index ~= "__index") and (index ~= "_M")then
         local t = type(v)
         if (t == "function") then
           w(index, parent)
         elseif (t == "table") then
           recursive(v, index, level + 1)
         end
       end
     end
   end
   recursive(_G, nil, 0)

it only consider functions because is what I aimed, it will only go deep enough
 
Code:
function traverse(t, level, seen)
    level = level or 1
    seen = seen or {}
    if seen[t] then
        return io.write(("\t"):rep(level), "...\n")
    end
    if level == 1 then
        io.write("{\n")
    end
    seen[t] = true
    for i, x in pairs(t) do
        io.write(("\t"):rep(level))
        io.write("[", (type(i) == "string" and '"' .. i .. '"' or tostring(i)), "] = ")
        if type(x) == "table" then
            io.write("{\n")
            traverse(x, level + 1, seen)
            io.write(("\t"):rep(level), "}")
        elseif type(x) == "string" then
            io.write('"', x, '"')
        else
            io.write(tostring(x) or "cannot convert to string")
        end
        io.write(",\n")
    end
    if level == 1 then
        io.write("}\n")
    end
end

io.stdout = io.open("out.txt", "w")
io.output(io.stdout)
traverse(_G)

Output: http://pastebin.com/jNc3mzSk (Lua 5.3)
 
Back
Top