[REL] wScriptSource v0.1.0 - Tiny Source Debugger Mod

Discussion in 'Mod Discussions' started by cptawesomer, March 3, 2014.

  1. cptawesomer

    cptawesomer Member

    Messages:
    29
    Likes Received:
    28
    Hey all,

    I'm new to modding PA, but this afternoon I started fooling around with PA's modding capabilities. I instantly missed something I have in traditional webdevelopment: proper access to sources and breakpoints in the debugger!

    Untangling source files & enabling breakpoints
    I digged a little futher and I noticed the vanilla game JS loads the mods by reading them and appending them into a <script> tag in the body of the game UI. This mod alters the behaviour in such a way that the mod JavaScript sources are added by linking the source instead of appending it.

    Caution!
    This mod shadows the shared "common.js" file. This is a tool to be used for debugging only. It has helped me quite a bit to look into how other mods work by being able browse through their sources much easier and helped me debug my own. It's easy to turn on and off when needed in PAMM.

    Screenshot
    A view of mod sources and breakpoints in the Coherent UI Debugger:
    [​IMG]
    Maybe there are other ways to get breakpoints/sources working, but this helped me quite a bit and I wanted to share my work. I hope it will help someone else aswell!

    Now available on PAMM!

    Repository can now be found on GitHub:

    https://github.com/TheMagnificentWerty/wScriptSource

    Attached Files:

    Last edited: March 6, 2014
  2. tatsujb

    tatsujb Post Master General

    Messages:
    12,884
    Likes Received:
    5,379
    <picture is now part of the main post, thanks tatsujb>
    Last edited by a moderator: March 3, 2014
  3. cptawesomer

    cptawesomer Member

    Messages:
    29
    Likes Received:
    28
    Thanks tatsujb, you're awesome.
  4. cola_colin

    cola_colin Moderator Alumni

    Messages:
    12,074
    Likes Received:
    16,221
    WOW
    does this work without flaws though? 2 things:

    1.) Doesn't this change how relative paths in the js resolve?
    2.) The blackscreenfix fixes blackscreens by avoiding the linkage of css files, just like it is avoided for js files in the default game. I wonder if this causes blackscreens due to the linked js files.

    EDIT:
    so basically @Uber: Why not linking the js files in the first place?
    There has to be a reason why one of you guys chose to initially embed js, but link css.
  5. cptawesomer

    cptawesomer Member

    Messages:
    29
    Likes Received:
    28
    Excellent question, actually it doesn't. Coincidentally it seems that PAStats does not work anymore with this mod enabled. I haven't thorougly tested all other mods but at first glance most seem to still work fine.

    1) I don't think so, it only changes the way the scripts are included everything else stays te same. I am more worried about timing issues as the scripts are retrieved asynchronously vs synchronously without this mod enabled.
    2) This I do not know. I have been experiencing black screens a lot lately, but I can't say I have noticed an increase when I used this mod. A simple F5 refresh fixes black screen problems for me everytime so far since Gamma.

    Edit:
    Yes this is a good question! It seems that not ALL JS sources can be linked, I tried this and the game wouldn't start properly and I would see console errors about stuff like $ being undefined. I think a race condition occurs because the source linking takes a bit of time and is done asynchronously. The normal way it loads stuff seems to be synchronously.
    Last edited: March 3, 2014
  6. LavaSnake

    LavaSnake Post Master General

    Messages:
    1,620
    Likes Received:
    691
    Wow, if this works then it's my new favorite mod! Thanks a ton.
  7. cola_colin

    cola_colin Moderator Alumni

    Messages:
    12,074
    Likes Received:
    16,221
    So PA Stats is kinda a special case of a mod, as you might have noticed it is loaded from an external source.
    The point about asynchronous loading is a good one.
    The PA Stats loader first calls loadMod on a global js file and then proceeds to add a scene specific file to the array of mod files that will soon after be loaded by PA. That scene specific file is depending on the global js file. So if the loading of the global js file is not yet finished for whatever reason the whole thing fails.

    ... blind guess haven't really tested anything.

    EDIT: about the blackscreens:
    try to load css files via the method that was used by js before, do you get blackscreens like that?
    If not it would mean that the blackscreen issue is specific to css files.

    EDIT 2:
    Thinking of timing issues:
    Maybe the whole blackscreen issue is a race condition that happens because css files are loaded async by default via linking? (are they async? I have no idea...)

    EDIT 3:
    Yeah pretty sure timing issues kill the way PA Stats loads via this kind of file:

    (http://www.nanodesu.info/stuff/pa/mods/live/pastats/pa_stats_loader.js)
    Code:
    var paStatsBaseDir = typeof statsDevelopmentNeverUseThisNameAnywhereElseIDareYou != 'undefined' ? 'coui://pa_stats/' : 'http://nanodesu.info/stuff/pa/mods/live/pastats/';
    (function() {
        if (typeof paStatsGlobal === 'undefined') {
            var b = paStatsBaseDir;
            loadScript(b+'lib/unitInfoParser.js');
            loadScript(b+'scenes/global.js');
            var c = b+'lib/captureLobbyId.js';
            scene_mod_list['server_browser'].push(b+"scenes/ranked_matcher/server_browser.js");
            scene_mod_list['start'].push(b+"scenes/ranked_matcher/start.js");
            scene_mod_list['connect_to_game'].push(c);
            scene_mod_list['server_browser'].push(b+"scenes/server_browser.js");
            scene_mod_list['new_game'].push(b+"scenes/new_game.js");
            scene_mod_list['game_over'].push(b+'scenes/game_over.js');
            scene_mod_list['live_game'].push(b+'lib/alertsManager.js');
            scene_mod_list['live_game'].push(b+'scenes/live_game.js');
            scene_mod_list['lobby'].push(b+'scenes/lobby.js');
            scene_mod_list['start'].push(b+'scenes/start.js');
            scene_mod_list['settings'].push(b+'scenes/settings.js');
        }
    }());
    Basically this piece of code expects that it is loaded as a global mod right before the scene will loop through it's scene_mod_lists array. So the loader adds the js file that needs to be loaded "just in time". This just in time works 100% perfect with the default system because it is synchronous. The asynchronous way probably executes this piece of code in parallel to the loop that is supposed to be altered by me adding stuff into those arrays.

    EDIT 4:
    It might be possible to fix PA Stats by not using the scene array and instead checking the current page location and acting on that, calling loadScript if necessary.
    Last edited: March 4, 2014
  8. wondible

    wondible Post Master General

    Messages:
    3,299
    Likes Received:
    2,089
    The typical reason is that with ajax-eval it's possible to perform synchronous loading. Without looking at uber's loader, I'm assuming that mod loading is synchronous because I've had issues relating to the ko-binding time, which is performed after mod loading.

    I have run into interesting corner cases when using RequireJS in development; doing that to a mod that wasn't tested with async loading is bound to turn up a few issues.
  9. cptawesomer

    cptawesomer Member

    Messages:
    29
    Likes Received:
    28
    This could be true, look at the code from common.js below. This code is used to include CSS files. It seems to happen asynchronously:

    Code:
    function loadCSS(src) {
        console.log(src, "loading css");
        var link = document.createElement('link');
        link.href = src;
        link.type = "text/css";
        link.rel = "stylesheet";
        document.getElementsByTagName("head")[0].appendChild(link);
    }
    
    I geuss you changed this in your fix black screen mod?

    This is the change I made in common.js.: This is the original code in the same file to load javascript files:

    Code:
    function loadScript(src) {
        console.log(src, "loading script");
        var o = new XMLHttpRequest();
        try
        {
            o.open('GET', src, false);
            o.send('');
        }
        catch( err )
        {
            console.log("error loading " + src)
            return;
        }
        var se = document.createElement('script');
        se.type = "text/javascript";
        se.text = o.responseText;
        document.getElementsByTagName('head')[0].appendChild(se);
    }
    Here it retrieves the entire file and then appends it to the head of the UI and after finishing retrieving it (everything waits for this).

    This get overwritten (only for mods). Now they are included like this:

    Code:
    function loadModScript(src) {
    console.log(src, "loading script asychronously (wScriptSource)");
      
        var script   = document.createElement("script");
        script.type  = "text/javascript";
        script.src   = src;    // use this for linked script
        document.getElementsByTagName('head')[0].appendChild(script);
    }
    
    I have tried making the other JavaScript wait for this through this piece of code in several places like start.js and common.js.
    Code:
    $(window).load();
    But there is a lot of JavaScript files that all link to eachother and are dependent upon eachother. It should be possible though, because seems to wait for all JavaScript to finish. There is lots of stuff triggering on
    Code:
    $(window).ready();
    but this doesn't wait for <script> sources to load and replacing it with .load(); creates race condition issues and doesn't solve the problem (so far).

    This seems to be exactly what is happening. Yeah this could be a good solution, not necessary perse though as I don't think Uber is going to change the way they do this anytime soon. If you want to be able to use this mod you might have to though.

    I might dig into this issue a bit further and get a view of the dependency tree in the JS files. It might be as simple as finding the right piece of JavaScript code and make it wait for the $(window).load(); event.

Share This Page