1. Updated Resource Submission Rules: All model & skin resource submissions must now include an in-game screenshot. This is to help speed up the moderation process and to show how the model and/or texture looks like from the in-game camera.
    Dismiss Notice
  2. DID YOU KNOW - That you can unlock new rank icons by posting on the forums or winning contests? Click here to customize your rank or read our User Rank Policy to see a list of ranks that you can unlock. Have you won a contest and still havn't received your rank award? Then please contact the administration.
    Dismiss Notice
  3. The 18th Icon Contest is ON! Choose any ingame unit and give him/her Hero abilities. Good luck to all.
    Dismiss Notice
  4. The Secrets of Warcraft 3 have revealed interesting works. The RESULTS for Abelhawk's Mini-Mapping Contest #15 have come out!
    Dismiss Notice
  5. Contestants are to create a scene set in the Stone Age. Come and see what you can come up with. We wish you the best of luck!
    Dismiss Notice
  6. Colour outside the lines! Techtree Contest #13 is a go. The contest is optionally paired.
    Dismiss Notice
  7. Night Rider gained several songs for his journey. The poll for the 12th Music Contest has started. Check it out!
    Dismiss Notice
  8. Greetings cerebrates, our Swarm needs new spawners that will have numerous children. Join the HIVE's 31st Modeling Contest - Spawners and Spawned! The contest is optionally paired.
    Dismiss Notice
  9. Join other hivers in a friendly concept-art contest. The contestants have to create a genie coming out of its container. We wish you the best of luck!
    Dismiss Notice
  10. Check out the Staff job openings thread.
    Dismiss Notice
Dismiss Notice
60,000 passwords have been reset on July 8, 2019. If you cannot login, read this.

Compiling vJass and Wurst using VSCode

Discussion in 'JASS/AI Scripts Tutorials' started by Bannar, Apr 28, 2018.

  1. Bannar

    Bannar

    Joined:
    Mar 19, 2008
    Messages:
    3,087
    Resources:
    20
    Spells:
    5
    Tutorials:
    1
    JASS:
    14
    Resources:
    20

    Introduction


    More and more modders use script languages rather than GUI due to developer-friendly features and great possibilities that come with them.
    Vexorian's jasshelper brought vJass to the community many years ago, which soon became a pillar of Warcraft 3 modding.
    Unfortunately, project has not been maintained properly for years and none fixed the issues that arose during that time.
    Newest addition to the family, Wurst, brings refreshment to the table.
    While it might have been launched a bit too early given its previous state, its current form, without a doubt offers greater array of features and is a modern approach to war3 map development.
    It is also coupled nicely with VSCode, although, after reading the guide you should be able to use VSCode for vJass too.

    Goal of this short tutorial is to get user used to modern approach of map development and allow him to work with vJass and Wurst together in a single map.

    Note:
    This guide does not explain things in very detailed manner. Target is to present the problem and provide general answer.
    Once you have firm grasp over the subject, you will surely conquer any monster that you might face.

    Is it assumed that you are familiar with: jasshelper, vJass, Trigger Editor, wurst setup, basic wurst, and general usage of VSCode.

    Helpful links:
    Facts


    In a world dominated by vJass, it might not be easy to sneak wurst into the map.
    One cannot simply be told to rewrite entire map to wurst in one go.

    Let's state some key facts:
    • Compatibility is important, vJass cannot be simply just scrapped
    • Vast majority of war3 modders use vJass
    • Heavily favored over Wurst by new users because of streamlined learning curve: GUI -> Jass -> vJass
    Users which want to include wurst code in their map face compatibility problems.
    This is because wurst is not fully compatible with vJass, example:
    • Different reserved keywords: construct
    Solution: rename your variables​

    • Forbidden native TriggerRegisterVariableEvent
    Solution: use TriggerEvaluate directly, rather than real variable manipulation​

    Target



    Need of mechanism for handling situation when both, wurst and vjass code exist in the map.


    Behind the scenes


    vJass and jasshelper:

    Pictures below show high-level view of build process

    1) Input single .j file into jasshelper, which outputs pure jass file readable by Warcraft3.
    [​IMG]

    2) Inject compiled.j file into template map to receive fully functional w3x file.
    [​IMG]

    3) Via Warcraft3, players can experience beauty of our map.
    [​IMG]

    Process path for wurst is similar with exception of jasshelper being replaced by wurst compiler.


    Combing Wurst and vJass


    An output for jasshelper compilation operation is .j file with name specified in the command containing compiled code to pure jass. For build operation, is it map w3x file given the name.
    An output for standard build wurst map operation is compiled.j and map file e.g.: WurstRunMap.w3x. There is no separate compilation task.

    The key thing to note, which we gonna take advantage of, is fact that wurst compiler searches for war3map.j file within <your_project_path>/wurst directory. This concept is shared with you during the "Hello World" of wurst, that is, creation of your first wurst project. Once saved, you will notice the new .j, war3map file, appearing in your wurst directory.
    Wurst compiler will combine both, wurst scripts and war3map.j file together and attempt to compile them into a single compiled.j file.

    Let's modify previously shown process path of map creation to reflect what we have just said:

    1) Use jasshelper to create map script file and place it under /wurst directory.
    [​IMG]

    2) Combine both, wurst and war3map to create compiled.j file.
    [​IMG]

    Afterwards, the compiled.j will be used for map creation, just like for jass-only map.


    Work, work



    Pictures displaying origination of Happy gamer for vJass do not list .j file (notice the lack of plural) by mistake.
    Let's checkout commands which we use when compiling vJass with jasshelper
    Code (Text):
    // compile
    jasshelper.exe --scriptonly <path_to_common.j> <path_to_blizzard.j> <path_to_input.j> <path_to_output.j>

    // build
    jasshelper.exe <path_to_common.j> <path_to_blizzard.j> <path_to_mapscript.j> <path_to_map.w3x>
     
    Notice that both arguments <path_to_input.j> and <path_to_mapscript.j> are expected to be a single file each. Thus one is forced to generate a single .j file from all of our jass scripts visible in World Editor's Trigger Editor.

    We are tasked with the following:
    • Extract and compile our vJass map code into a single war3map.j file
    • Have the war3map.j under /wurst directory
    • Run wurst compiler to generate final compiled.j file

    Once you read this through and give yourself a moment for reflection, you will realize how tedious would be to work with a single .j file which might be tens of thousands lines long.
    This is where our next player comes in.. the VSCode.

    On wurst side, there not much left to do. As said already, it is coupled nicely with VSCode. Building and running map from the IDE is fully automated.
    The highlighter and syntax checker are great, auto-completion is here too. You wouldn't tell a difference from working with typical programming language in VSCode.

    Automation is key here. Launching everything manually once or twice is not a problem. However, doing this repeatedly will prove to be a nuisance.

    Below are displayed the standard commands available for wurst map:

    [​IMG]

    Ideally, we would like to see something similar for our old vJass friend:

    [​IMG]

    To achieve our goal, we are going to take advantage of VSCode tasks.

    It was mentioned previously that we need a single .j file for jasshelper to not complain about parameters. It was also noted that it is tedious to work with one big file on a daily basis.
    However, nowhere it is said how the organization of files must look like before the compilation. We need that single file only for the moment of compilation. Before and after, doesn't matter.
    Since the spirit of this tutorial is: a modern approach to war3 map development, we would like to keep things that way.
    Our neighbour, wurst, already acts as a good example. All wurst files are kept under /wurst directory, and their organization is yours to decide.
    We are going to copy that approach, and create /jass directory where all the .j files are going to reside.

    If you want, you can even mirror script organization from World Editor's Trigger Editor. In such case, triggers would be replaced by .j files and categories by folders.

    To sum up what we have just said:
    • jasshelper expects single .j file as an input (apart from common.j and blizzard.j)
    • Scripts have to be extracted and placed under single directory
    • Content of those scripts has to be combined and only then passed to jasshelper for compilation
    Example below shows the organization of map project where vJass and wurst and present simultaneously:

    [​IMG]

    VSCode tasks can be used to execute simple task for current workspace which is great when we want to perform repeatable operations, such as building and running maps. Array of available tasks should be stored in task.json file under /.vscode directory.

    What we need?
    • task.json file to specify range of tasks available
    • Scripts to perform actual tasks
    For latter, I've decided to go for powershell which is preferred shell-oriented scripting language on Windows machines. You can choose whatever language you prefer and are comfortable with. Shell scripts, python scripts. It's all fine. Just be sure to edit 'command' accordingly.

    Let's show an example, because example is worth more than a thousand words:
    Code (Text):
        "tasks": [
            {
                "label": "Compile map",
                "type": "shell",
                "command": "powershell -ExecutionPolicy ByPass -File ./compile.ps1",
                "group": {
                    "kind": "build",
                    "isDefault": true
                }
            }
        ]
    Using VSCode task page reference, here is simple description of task fields:
    • label: The task's label used in the user interface.
    • type: The task's type. For a custom task, this can either be shell or process.
    • command: The actual command to execute.
    • windows: Any Windows specific properties. Will be used instead of the default properties when the command is executed on the Windows operating system.
    • group: Defines to which group the task belongs. Usually it ends up being "test" or "build".
    • presentation: Defines how the task output is handled in the user interface.
    It should be clear now how this simple task operates - and remember, you always want to keep it simple.
    You give it name that is going to be depicted on the task list, kind, and command. This is the same command that you would execute from your shell so it is easy to test this out if something goes wrong.

    Using this method, one can create several tasks. Personally, I recommend having:
    • compile-only task, without map script injection
    • compile-only task, without map script injection with --debug option added
    • build task, which compiles map script and injects it to the map
    • run task, which works as previous one, but runs the map afterwards
    I would not forgive myself without providing you with yet another example. This time with compile-task script. Our goal is to combine the content of all files under /jass directory in order for jasshelper to compile the map script:
    Code (Text):

    # Create GeneratedJ file from content of all .j and .zn files
    $InputFiles  = Get-ChildItem -Path $JassFolder -Include *.j, *.zn -Recurse
    New-Item $GeneratedJ -ItemType File -Force

    ForEach ($File in $InputFiles)
    {
        If ($File.Extension -eq '.zn')
        {
            Add-Content -Path $GeneratedJ -Value "//! zinc"
            Get-Content -Path $File | Add-Content $GeneratedJ
            Add-Content -Path $GeneratedJ -Value "//! endzinc"
        }
        Else
        {
            Get-Content -Path $File | Add-Content $GeneratedJ
        }
    }

    # Run jasshelper to perform actual compilation of map script
    $Params = $args + @('--scriptonly', $CommonJ, $BlizzardJ, $GeneratedJ, $OutputJ)
    & $Jasshelper $Params
     
    This implementation is straight forward. Create new file as a sum of content of all files under JassFolder. Once generated, this file is passed to jasshelper for compilation.
    Notice the special care has been taken for Zinc. Preprocessor directives are appended before and after every .zn file to ensure that jasshelper will indeed treat them as Zinc files. If your .zn files already have those directives, you can drop the 'If'.


    Summary



    In order to compile map where vJass and Wurst are both present using VSCode task automation one needs to:
    1. Extract scripts from Trigger Editor and put them under single directory
    2. Create simple script for combining content of all files and launching jasshelper
    3. Have task.json prepared and present in his workspace directory
    4. Compile vJass scripts, using compile task. On successful compilation, war3map.j should be present in /wurst folder
    5. Run build or run wurst map task from VSCode
    Right after script extraction and first compilation you might face issues such as: missing variable, function not found. This is especially true if you are going to adjust map containing pure jass or converted GUI code using this approach. You will have to manually repair the order of your files within /jass directory to fix those. I recommend having separate .j file for globals and separate for map main functions. Ensure that the former is always on top (put it into directory with name starting with '0') and the latter is the end (have it outside of any directory, make it start with 'z' letter) of file hierarchy.

    Live example of map which contains jass, GUI, vJass, Zinc and Wurst code combined: Island Troll Tribes. Map is currently under transition of becoming wurst-only map.

    Is the reverse possible? Meaning, compiling wurst map script first, then appending some jass scripts and outputting compiled.j via jasshelper?
    It is, afterall, wurst compiler outputs two files, compiled.j and w3x map file (e.g.: WurstRunMap.w3x) into _build directory.
    You can use the exact same method described above for integrating Wurst code into vJass map - combine the /_build/compiled.j with your .j files and pass that to jasshelper. The output of this, the combined map script .j file, can be used with jasshelper build command to generate functional map.
    However, before you proceed, ask yourself if perhaps, you are not doing something wrong. If you are planning to use wurst, you should not be thinking about injecting vJass code into it.

    Something is missing? Not implemented? Frotty and the boyz are more than happy to hear you out!
    You can meet them on github and their irc, see wurst contact page.



     
    Last edited: Apr 29, 2018
  2. Bannar

    Bannar

    Joined:
    Mar 19, 2008
    Messages:
    3,087
    Resources:
    20
    Spells:
    5
    Tutorials:
    1
    JASS:
    14
    Resources:
    20
    Reserved.
     
  3. MyPad

    MyPad

    Spell Reviewer

    Joined:
    May 9, 2014
    Messages:
    1,270
    Resources:
    6
    Models:
    1
    Icons:
    1
    Spells:
    3
    JASS:
    1
    Resources:
    6
    Quite a definitive approach you have right here. This explains quite a lot on the tasks in VS Code, which I have no knowledge of.

    Can one do the heavy lifting of updating jassHelper to use the more modern approach, outsourcing the script to VS Code, instead of many who will try and fail at said task? This would mean that only one has to do it and bundle the entire thing, rather have the following scenario that I described occur.
     
  4. Bannar

    Bannar

    Joined:
    Mar 19, 2008
    Messages:
    3,087
    Resources:
    20
    Spells:
    5
    Tutorials:
    1
    JASS:
    14
    Resources:
    20
    Professional approach to software development:
    - isolate bugs from features
    - fix bugs first, ensure sw is working
    - only then, start adding new features

    Long story short: none ever fixed known issues properly without contaminating jasshelper with new features which were never finished eventually leading to that version being unusable.
     
    Last edited: Apr 29, 2018
  5. Frotty

    Frotty

    Wurst Reviewer

    Joined:
    Jan 1, 2009
    Messages:
    1,406
    Resources:
    11
    Models:
    3
    Tools:
    1
    Maps:
    5
    Tutorials:
    1
    Wurst:
    1
    Resources:
    11
  6. Fasolace

    Fasolace

    Joined:
    Sep 14, 2009
    Messages:
    240
    Resources:
    6
    Skins:
    1
    Template:
    5
    Resources:
    6
    I want to learn to use wurst but the tasks in VSCode don't show up when I wanto ro run the map etc. How do I fix this?
     
  7. Bannar

    Bannar

    Joined:
    Mar 19, 2008
    Messages:
    3,087
    Resources:
    20
    Spells:
    5
    Tutorials:
    1
    JASS:
    14
    Resources:
    20
    Try: [CTRL + SHIFT + P] mate.

    Edit: Glad it worked out : )
     
    Last edited: May 10, 2018
  8. PurgeandFire

    PurgeandFire

    Code Moderator

    Joined:
    Nov 11, 2006
    Messages:
    7,427
    Resources:
    18
    Icons:
    1
    Spells:
    4
    Tutorials:
    9
    JASS:
    4
    Resources:
    18
    Awesome tutorial. Really useful for people who want to migrate their maps to wurst (or take advantage of existing vJASS libraries), or just switch up their workflow a bit. I love the amount of detail and the nifty diagrams.

    Approved. One request though: I think it would be helpful to include the build task and run task script. :] This tutorial is really useful for people who want to configure their own workflow, but I imagine a lot of people will just want some ready-made scripts that they can plug in to VSCode and be on their way.
     
  9. Trokkin

    Trokkin

    Joined:
    Jan 23, 2015
    Messages:
    97
    Resources:
    1
    Tutorials:
    1
    Resources:
    1
    Tutorial is great. Everything else was already said.

    Actually, instead of updating jasshelper, one could create proper vscode extension that will solve compilation problems with vjass. And maybe add proper language support, at least for syntax highlighting. There is already one extension, but it isn't being updated and highlight do not support loops or bj/natives.
    Then two extensions for two languages could be combined through settings file so that workflow for two languages will become even more smooth and easy.

    But combination of both wurst and vjass seems for me kinda bad. They both use different approach for compiled naming which may result in name collision, and they can't access each other's part. Well, like, wurst can use functions from war3map.j, but not vice versa, which at best means that vjass part can be used in a pretty ugly to use, because of the compiled function names.
    Nice that it allows for a smooth transition from vjass to wurst, but I can hardly imagine that somebody would actually develop a map sitting on these two chairs.
     
  10. Chaosy

    Chaosy

    Joined:
    Jun 9, 2011
    Messages:
    10,600
    Resources:
    18
    Maps:
    1
    Spells:
    11
    Tutorials:
    6
    Resources:
    18
    I have a question and see two possibilities, both give unwanted answers.

    It's regarding the conversion.

    So let's say I have my huge-ass map with a hundred triggers.
    I extract the gigantic .j file with all the code and place it in the jass folder.

    Problems:
    1. The script is an unreadable state and I cannot edit it without my eyes bleeding.
    1b. Which means I need to extract each time I make a jass update.
    2. The code is in a giant file which makes it hard to update

    The desired outcome is that I have a bunch of .j files of uncompiled code
    Supposedly the task should handle this? but I do not understand how.
    Jasshelper is no a native program on my computer so I got no clue how the task is supposed to find a copy of jasshelper and run it.
    Maybe I went through the tutorial a bit quickly but I did not see any instruction to download jasshelper which make me confused.
     
  11. Frotty

    Frotty

    Wurst Reviewer

    Joined:
    Jan 1, 2009
    Messages:
    1,406
    Resources:
    11
    Models:
    3
    Tools:
    1
    Maps:
    5
    Tutorials:
    1
    Wurst:
    1
    Resources:
    11
    It's in the summary. The tutorial says the user has to extract their jass scripts from triggereditor into separate files. If you just take a map, jasshelper will output 1 big .j.
    Also, you of course aren't supposed to modify the compiled .j files. These are just generated so wurst can parse and interact with your (v)jass code.
    This makes your points kinda moot. You're not supposed to touch generated code and I don't get why you would ever even want to do that.


    Neither is wurst? In fact, there are no installation instructions at all, I guess this is expected. Download JH binaries and put them somewhere where you can call the .exe from the vscode task.
    I suppose this should be added to the tutorial somehow.
     
  12. Chaosy

    Chaosy

    Joined:
    Jun 9, 2011
    Messages:
    10,600
    Resources:
    18
    Maps:
    1
    Spells:
    11
    Tutorials:
    6
    Resources:
    18
    The whole point of having an external jass folder is so I can edit the code on demand from vscode. (at least for me)
    Otherwise I see no difference than just using the editor and remove all the extra steps for no benefit.
    It is also supposed to be automated, and updating jass code is clearly not automated if I need to extract code manually each time.

    This is why I think it is very odd that the conversion step from uncompiled jass to compiled is not included.
    If it is not an application which appears in the list of installed programs; I need to specify a path to the install path, something which is missing from the script as far as I can tell.
    I do not know powershell (or any shell language really) so I have no clue how to do it myself.
     
  13. Frotty

    Frotty

    Wurst Reviewer

    Joined:
    Jan 1, 2009
    Messages:
    1,406
    Resources:
    11
    Models:
    3
    Tools:
    1
    Maps:
    5
    Tutorials:
    1
    Wurst:
    1
    Resources:
    11
    Yes Chaosy, obviously you edit your raw vJass resources in vscode. Those raw files are then passed to JH, which generates the compiled Jass. This compiled Jass is used by Wurst and you shouldn't touch it.

    e: maybe we wait for the tutorial creator to clear up these concerns :) I might understand it differently too.
     
  14. Chaosy

    Chaosy

    Joined:
    Jun 9, 2011
    Messages:
    10,600
    Resources:
    18
    Maps:
    1
    Spells:
    11
    Tutorials:
    6
    Resources:
    18
    Alright I gave this another go.

    I have some success but also came across more issues regarding this approach.

    The problem comes from the fact that jasshelper forces you to have a main function in your jass code.
    Easily fixed.
    However, this means my code cannot co-exist with the default map script, since it also use a main function which causes collision.
    This forces me to scrap the standard war3map.j (which is said in the tutorial, but not explaining why) and overwrite it with my own

    There are several drawbacks to this as there are a lot of things defined in the war3map.j
    Such as preplaced unit positions. (and a bunch of other stuff, but this is the dealbreaker for me)

    The simple fix for this would be if wurst had a way to specify the location of the extracted war3map.j
    Because if war3map.j was automatically put in the jass folder it would compile perfectly
    Doing it manually each time I move a unit is too bothersome to me.

    My opinion aside, I think it should be worth pointing out the downsides in the tutorial

    edit: You could remove the war3map.j from the compile.ps1 after using it to compile which would remove the problem.
    With the 'minor' downside of having to run three commands every time you move a unit
    compile vjass > build wurst > run wurst
     
    Last edited: Nov 17, 2018
  15. Frotty

    Frotty

    Wurst Reviewer

    Joined:
    Jan 1, 2009
    Messages:
    1,406
    Resources:
    11
    Models:
    3
    Tools:
    1
    Maps:
    5
    Tutorials:
    1
    Wurst:
    1
    Resources:
    11
    Imho this workflow isn't something recommended to do, just explains how to do it if you plan to maintain a legacy map with wurst.

    Shouldn't there be a way to pass the map/war3map.j to JH? Since this happens automatically in JNGP/wex.

    Maybe post your concrete example? Perhaps we can find a neat solution using vscode tasks.
     
    Last edited: Nov 18, 2018
  16. Chaosy

    Chaosy

    Joined:
    Jun 9, 2011
    Messages:
    10,600
    Resources:
    18
    Maps:
    1
    Spells:
    11
    Tutorials:
    6
    Resources:
    18
    There is.

    So if my compile script does the following:

    combine "./wurst/war3map.j" + all .j files in "./jass"
    Output "./wurst/vjass.j

    Now we have war3map.j and vjass.j with a main function which wont work.

    My best solution would be to have some sort of file watcher that automatically moves the war3map.j into the jass directory when it is generated in the wurst folder.
    Because the main issue to me is that the war3map.j is placed in the wurst folder which injects it into the map. Combined with the fact that even if I do something like move the war3map.j after compiling.. problem re-emerge when I test the map, forcing me to compile after every single test which is just annoying

    Alternatively make some script to merge the two files which I think is pretty complicated. And also it is just a bandaid solution.