• 🏆 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] Debug Utils (Ingame Console etc.)

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
I've been speculating on the massive scope of a project it would be to try to integrate this source mapping functionality into TriggerHappy's W3TS. Basically, TypeScript2Lua does have a source mapping feature (disabled by default due to the absence of the debug library), but with this tool it would be possible to synthesize the stack trace in a way that it offsets the line numbers based on the concatenation of the original war3map.lua file with the TypeScript2Lua file, and by counting the newline characters it will be able to generate an offset. And you would thus be able to get full stack traces to the original TypeScript source code. Sounds wonderful, right? The problem is that I am still new to the idea of bundling TypeScript and Lua in the same package. I think for systems like this, that it only makes sense to keep them written in Lua, because they are far too low-level to be useful otherwise.

Stuff like Debug.beginFile/endFile would obviously not be needed in that case, because TypeScript2Lua has its own map that traces back to the TypeScript source.

Due to the close nature to the build process, this would have to be directly bundled into w3ts, in order to know how many original lines of code were in the war3map.lua file, so the stacktrace gives fake offsets. This would be problematic if there is an error picked up in some GUI code that was pre-packaged with the map.

It also makes me wonder, why not just include the war3map.lua as top-level source code when compiling with TSTL, thus eliminating any need for hacky offsets. The mapped traceback would work well to identify standard war3map.lua problems.

So maybe the sanest approach is to just not try to do anything with the source map at all, and just let people sift through the compiled Lua code. Who knows. Some feedback would be welcome.

Edit - here is the beginning of an attempt to provide the necessary API to TypeScript2Lua. This would need to ensure that it is placed above the transpiled Typescript code itself, in order to ensure that TypeScript2Lua uses it instead of the nonexistent debug global:

Lua:
debug = {
    traceback = function(thread, message, lineNumber)
        local level, n, traceback, msg, last = lineNumber or 1, 0, {}, nil, ""
        repeat
            _,msg = pcall(error, "", level)
            if msg ~= "" and msg ~= skipThisLine1 and msg ~= skipThisLine2 and msg ~= last then
                n = n + 1
                traceback[n] = msg
                last = msg
            end
            level = level + 1
        until level == 200
        local i, results = 0, {}
        repeat
            msg = traceback[n - i]
            i = i + 1
            results[i] = msg
        until i == n
        return table.concat(results)
    end,
    getinfo = function()
        return {short_src = 'war3map.lua'}
    end
}

Happy to hear more of @TriggerHappy 's thoughts on this one.
 
Last edited:
Level 20
Joined
Jul 10, 2009
Messages
474
Interesting. I've neither used Typescript nor closely looked at any language converter, so I can't really contribute good thoughts. I wonder though, would a line in the compiled Lua code even match a single line in the TS source code 1-to-1? Might there be cases where one line of TS becomes multiple lines of Lua or the other way around, so you wouldn't necessarily be able to precisely convert an error message on paper? Even the order of lines might have changed during conversion, which is even harder to deal with.
So maybe the sanest approach is to just not try to do anything with the source map at all, and just let people sift through the compiled Lua code.
That sounds right to me, assuming that the compiled code is somewhat readable by humans and comparable to the original (same structure, same variable names, not minified). It requires a certain level of Lua knowledge, but you have a direct correlation of the code and the error in question.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
Thanks for your feedback!

I wonder though, would a line in the compiled Lua code even match a single line in the TS source code 1-to-1? Might there be cases where one line of TS becomes multiple lines of Lua or the other way around, so you wouldn't necessarily be able to precisely convert an error message on paper? Even the order of lines might have changed during conversion, which is even harder to deal with.

As long as I can ensure debug.traceback() is able to be overridden before TSTL caches it, AND luamin doesn't warp it, AND I directly implement a line number offset for the unadultered contents of war3map.lua then yes, the source map works. TSTL is very well thought through.

That sounds right to me, assuming that the compiled code is somewhat readable by humans and comparable to the original (same structure, same variable names, not minified). It requires a certain level of Lua knowledge, but you have a direct correlation of the code and the error in question.

I think that'll be my first checkpoint. Just ensuring that the stacktrace for runtime errors will display using this workaround to avoid dependencies on the debug library.
 
Level 20
Joined
Aug 13, 2013
Messages
1,696
hi @Eikonium ,when using:
Lua:
CinematicFadeBJ( bj_CINEFADETYPE_FADEIN, 5.00, "ReplaceableTextures\\CameraMasks\\Black_mask.blp", 0.00, 0.00, 0.00, 0.00 )
im getting these kind of errors:
1708027112464.png

here's the wrappers of it just in case:
JASS:
function CinematicFadeBJ takes integer fadetype, real duration, string tex, real red, real green, real blue, real trans returns nothing
    if (fadetype == bj_CINEFADETYPE_FADEOUT) then
        // Fade out to the requested color.
        call AbortCinematicFadeBJ()
        call CinematicFadeCommonBJ(red, green, blue, duration, tex, 100, trans)
    elseif (fadetype == bj_CINEFADETYPE_FADEIN) then
        // Fade in from the requested color.
        call AbortCinematicFadeBJ()
        call CinematicFadeCommonBJ(red, green, blue, duration, tex, trans, 100)
        call FinishCinematicFadeAfterBJ(duration)
    elseif (fadetype == bj_CINEFADETYPE_FADEOUTIN) then
        // Fade out to the requested color, and then fade back in from it.
        if (duration > 0) then
            call AbortCinematicFadeBJ()
            call CinematicFadeCommonBJ(red, green, blue, duration * 0.5, tex, 100, trans)
            call ContinueCinematicFadeAfterBJ(duration * 0.5, red, green, blue, trans, tex)
            call FinishCinematicFadeAfterBJ(duration)
        endif
    else
        // Unrecognized fadetype - ignore the request.
    endif
endfunction

function AbortCinematicFadeBJ takes nothing returns nothing
    if (bj_cineFadeContinueTimer != null) then
        call DestroyTimer(bj_cineFadeContinueTimer)
    endif

    if (bj_cineFadeFinishTimer != null) then
        call DestroyTimer(bj_cineFadeFinishTimer)
    endif
endfunction

function CinematicFadeCommonBJ takes real red, real green, real blue, real duration, string tex, real startTrans, real endTrans returns nothing
    if (duration == 0) then
        // If the fade is instant, use the same starting and ending values,
        // so that we effectively do a set rather than a fade.
        set startTrans = endTrans
    endif
    call EnableUserUI(false)
    call SetCineFilterTexture(tex)
    call SetCineFilterBlendMode(BLEND_MODE_BLEND)
    call SetCineFilterTexMapFlags(TEXMAP_FLAG_NONE)
    call SetCineFilterStartUV(0, 0, 1, 1)
    call SetCineFilterEndUV(0, 0, 1, 1)
    call SetCineFilterStartColor(PercentTo255(red), PercentTo255(green), PercentTo255(blue), PercentTo255(100.0-startTrans))
    call SetCineFilterEndColor(PercentTo255(red), PercentTo255(green), PercentTo255(blue), PercentTo255(100.0-endTrans))
    call SetCineFilterDuration(duration)
    call DisplayCineFilter(true)
endfunction

function FinishCinematicFadeAfterBJ takes real duration returns nothing
    // Create a timer to end the cinematic fade.
    set bj_cineFadeFinishTimer = CreateTimer()
    call TimerStart(bj_cineFadeFinishTimer, duration, false, function FinishCinematicFadeBJ)
endfunction

function ContinueCinematicFadeAfterBJ takes real duration, real red, real green, real blue, real trans, string tex returns nothing
    set bj_cineFadeContinueRed = red
    set bj_cineFadeContinueGreen = green
    set bj_cineFadeContinueBlue = blue
    set bj_cineFadeContinueTrans = trans
    set bj_cineFadeContinueDuration = duration
    set bj_cineFadeContinueTex = tex

    // Create a timer to continue the cinematic fade.
    set bj_cineFadeContinueTimer = CreateTimer()
    call TimerStart(bj_cineFadeContinueTimer, duration, false, function ContinueCinematicFadeBJ)
endfunction
the function still works perfectly fine though however is it okay to just ignore those bj messages or there's still something to take note of? tia
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
hi @Eikonium ,when using:
Lua:
CinematicFadeBJ( bj_CINEFADETYPE_FADEIN, 5.00, "ReplaceableTextures\\CameraMasks\\Black_mask.blp", 0.00, 0.00, 0.00, 0.00 )
im getting these kind of errors:
View attachment 461948
here's the wrappers of it just in case:
JASS:
function CinematicFadeBJ takes integer fadetype, real duration, string tex, real red, real green, real blue, real trans returns nothing
    if (fadetype == bj_CINEFADETYPE_FADEOUT) then
        // Fade out to the requested color.
        call AbortCinematicFadeBJ()
        call CinematicFadeCommonBJ(red, green, blue, duration, tex, 100, trans)
    elseif (fadetype == bj_CINEFADETYPE_FADEIN) then
        // Fade in from the requested color.
        call AbortCinematicFadeBJ()
        call CinematicFadeCommonBJ(red, green, blue, duration, tex, trans, 100)
        call FinishCinematicFadeAfterBJ(duration)
    elseif (fadetype == bj_CINEFADETYPE_FADEOUTIN) then
        // Fade out to the requested color, and then fade back in from it.
        if (duration > 0) then
            call AbortCinematicFadeBJ()
            call CinematicFadeCommonBJ(red, green, blue, duration * 0.5, tex, 100, trans)
            call ContinueCinematicFadeAfterBJ(duration * 0.5, red, green, blue, trans, tex)
            call FinishCinematicFadeAfterBJ(duration)
        endif
    else
        // Unrecognized fadetype - ignore the request.
    endif
endfunction

function AbortCinematicFadeBJ takes nothing returns nothing
    if (bj_cineFadeContinueTimer != null) then
        call DestroyTimer(bj_cineFadeContinueTimer)
    endif

    if (bj_cineFadeFinishTimer != null) then
        call DestroyTimer(bj_cineFadeFinishTimer)
    endif
endfunction

function CinematicFadeCommonBJ takes real red, real green, real blue, real duration, string tex, real startTrans, real endTrans returns nothing
    if (duration == 0) then
        // If the fade is instant, use the same starting and ending values,
        // so that we effectively do a set rather than a fade.
        set startTrans = endTrans
    endif
    call EnableUserUI(false)
    call SetCineFilterTexture(tex)
    call SetCineFilterBlendMode(BLEND_MODE_BLEND)
    call SetCineFilterTexMapFlags(TEXMAP_FLAG_NONE)
    call SetCineFilterStartUV(0, 0, 1, 1)
    call SetCineFilterEndUV(0, 0, 1, 1)
    call SetCineFilterStartColor(PercentTo255(red), PercentTo255(green), PercentTo255(blue), PercentTo255(100.0-startTrans))
    call SetCineFilterEndColor(PercentTo255(red), PercentTo255(green), PercentTo255(blue), PercentTo255(100.0-endTrans))
    call SetCineFilterDuration(duration)
    call DisplayCineFilter(true)
endfunction

function FinishCinematicFadeAfterBJ takes real duration returns nothing
    // Create a timer to end the cinematic fade.
    set bj_cineFadeFinishTimer = CreateTimer()
    call TimerStart(bj_cineFadeFinishTimer, duration, false, function FinishCinematicFadeBJ)
endfunction

function ContinueCinematicFadeAfterBJ takes real duration, real red, real green, real blue, real trans, string tex returns nothing
    set bj_cineFadeContinueRed = red
    set bj_cineFadeContinueGreen = green
    set bj_cineFadeContinueBlue = blue
    set bj_cineFadeContinueTrans = trans
    set bj_cineFadeContinueDuration = duration
    set bj_cineFadeContinueTex = tex

    // Create a timer to continue the cinematic fade.
    set bj_cineFadeContinueTimer = CreateTimer()
    call TimerStart(bj_cineFadeContinueTimer, duration, false, function ContinueCinematicFadeBJ)
endfunction
the function still works perfectly fine though however is it okay to just ignore those bj messages or there's still something to take note of? tia
The "undefined global" thing can be disabled in the settings
 
Level 20
Joined
Jul 10, 2009
Messages
474
@FUJI As an alternative to @Bribe 's suggestion, you can search for the following lines inside DebugUtils and remove the comment-hyphens from the if- and the end-statement. Doing so will exclude bj-variables from the undeclare-globals-check, but still apply it to all other globals:
Lua:
--if string.sub(tostring(k),1,3) ~= 'bj_' then
    print("Trying to read undeclared global at " .. getStackTrace(4,4) .. ": " .. tostring(k)
        .. (settings.SHOW_TRACE_FOR_UNDECLARED_GLOBALS and "\nTraceback (most recent call first):\n" .. getStackTrace(4,200) or ""))
--end

When I wrote the code, I wasn't sure whether Blizzard intentionally nilled bj-variables in Blizzard.j or not, so I included these outcommented lines just in case 😅
 
Top