• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

Lua GetStackTrace

Status
Not open for further replies.
Level 24
Joined
Jun 26, 2020
Messages
1,852
I don't know if this was actually found, but there is a way to get the stack trace in W3 Lua, just using the error function, because is the unique function that can tell us what function called it and the function that called this and so on, so I did something like this:
Lua:
function GetStackTrace()
    xpcall(error, print, "Fourth", 7)
    xpcall(error, print, "Third", 6)
    xpcall(error, print, "Second", 5)
    xpcall(error, print, "First", 4)
end
Why from start 4?, because the first will refer to the xpcall function; the second, the GetStackTrace function; and probably you will add this right before an error will happen, so it will display what would be the third position.

This is the result:
1655178632407.png

Is not very clean, but is the better solution I can think. Pls give feedback.
 
Last edited:

~El

Level 17
Joined
Jun 13, 2016
Messages
557
It could be, but how can I know when stops?
needs some testing to figure out how "error" behaves when you go outside the stack
depending on what it does, collect the stacktrace in a loop and catch that behaviour and then terminate the loop
if it starts returning an empty string instead of a file location, then watch for that. if it keeps repeating the same message, check if we've seen that location already (but watch out for recursive functions)
i dont have a working wc3 install rn so i cant test it, but should be easy to figure out with some tinkering


unless it crashes the game, of course, lol
 
Level 24
Joined
Jun 26, 2020
Messages
1,852
@mori I can do that.
After testing I found that in a new map, I should have the error function inside a function when I using the xpcall to get the position, like this:
Lua:
function func()
    xpcall(function ()
        error("Pos", 1)
    end, print)
end
I don't exactly know what have of special my map to work like that before, but oh well.
I also could test it without W3 just installing Lua (for who use Windows 10: Windows - How to install Lua on Windows?)
 
Last edited:
Level 24
Joined
Jun 26, 2020
Messages
1,852
Ok, I got a better aproach, after testing I found the function error only returns the message and not the position once it reached the end of the stack trace, so I do this:

Lua:
do
    local prefix = "war3map.lua"
    local prefixLen = string.len(prefix)
    local list = {}
    local lastMsg = nil

    local function getPos(msg, pos)
        error(msg, pos)
    end

    local function store(msg)
        table.insert(list, msg)
        lastMsg = msg
    end

    function GetStackTrace()
        local stack = ""

        local i = 4
        local p = 1
        while true do
            xpcall(getPos, store, "- " .. p, i)
            if string.sub(lastMsg, 1, prefixLen) ~= prefix then break end
            i = i + 1
            p = p + 1
        end

        for j = #list - 1, 1, - 1 do -- Don't consider the last
            stack = stack .. list[j] .. "\n"
        end

        list = {}

        return stack
    end
end
And here is a map to test:
 

Attachments

  • Lua GetStackTrace.w3m
    18.4 KB · Views: 10

Wrda

Spell Reviewer
Level 26
Joined
Nov 18, 2012
Messages
1,887
Lua:
Test = function(chatMsg)
    local playerName = GetPlayerName(GetTriggerPlayer())
    local loadedFunc, error = load(chatMsg, playerName, "t")
    if loadedFunc ~= nil then
        DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "Player " .. playerName .. " executed the function:\r\n" .. chatMsg)
        loadedFunc()
    else
        DisplayTextToPlayer(GetTriggerPlayer(), 0, 0, error)
    end
end
Essentially this as a player chat event.
load's 2nd parameter is chuckname,
1655478541040.png

eof = end of file

I'm still not sure if this answers your question in its entirety.
 
Level 24
Joined
Jun 26, 2020
Messages
1,852
Lua:
Test = function(chatMsg)
    local playerName = GetPlayerName(GetTriggerPlayer())
    local loadedFunc, error = load(chatMsg, playerName, "t")
    if loadedFunc ~= nil then
        DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "Player " .. playerName .. " executed the function:\r\n" .. chatMsg)
        loadedFunc()
    else
        DisplayTextToPlayer(GetTriggerPlayer(), 0, 0, error)
    end
end
Essentially this as a player chat event.
load's 2nd parameter is chuckname,
View attachment 401409
eof = end of file

I'm still not sure if this answers your question in its entirety.
Ok, so how can I apply it to what I asked?
I remember that some functions calls could come from the blizzard.j.lua file, in that cases this GetStackTrace function could stop in that moments when it shouldn't, I could fix that, but is there other files that I should consider?
 
Level 24
Joined
Jun 26, 2020
Messages
1,852
Ok, I improved the system to also consider the blizzard.j.lua, and updated the test map
Lua:
do
    local prefixes = {"war3map.lua", "blizzard.j.lua"}
    local n = #prefixes
    local prefixesLen = {}
    for i = 1, n do
        prefixesLen[i] = string.len(prefixes[i])
    end
    local list = {}
    local lastMsg = nil

    local function getPos(msg, pos)
        error(msg, pos)
    end

    local function store(msg)
        lastMsg = msg
    end

    local function checkPrefixes()
        for i = 1, n do
            if string.sub(lastMsg, 1, prefixesLen[i]) == prefixes[i] then
                return true
            end
        end
        return false
    end

    function GetStackTrace()
        local stack = ""

        local i = 4
        local p = 1
        while true do
            xpcall(getPos, store, "- " .. p, i)
            if not checkPrefixes() then break end
            table.insert(list, lastMsg)
            i = i + 1
            p = p + 1
        end

        for j = #list, 1, -1 do
            stack = stack .. list[j] .. "\n"
        end

        list = {}

        return stack
    end
end
 

Attachments

  • Lua GetStackTrace.w3m
    18.8 KB · Views: 8
Status
Not open for further replies.
Top