• 🏆 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!

vJass2Lua WebApp (powered by JavaScript) - now supports ZINC!

This bundle is marked as pending. It has not been reviewed by a staff member yet.
This webapp can nearly instantly convert a JASS or vJass script file into a Lua script, using JavaScript.

Compared to cJass2Lua, this parses a script file thousands of times faster, and is very easy to add onto and tweak as needed. The input script can be reverted just by clicking the "Revert to vJass" button (note that this does not convert a script from Lua to vJass, it just converts it back to what it was given).

It converts all known JASS scripts into Lua.

It converts almost all vJass and Zinc scripts into Lua, including textmacros that take arguments. Textmacros and modules that would normally inline into a function (like Nestharus's CTL resources) will not be parsed correctly since Lua has no way to literally "macro in" text. Some minor syntax changes are needed to make things work with Lua, but the terminology stays roughly familiar.

How to run:

1a) Go to https://bribefromthehive.github.io/vJass2Lua and skip to step 3
OR
1b) Download the attached .zip file or copy the source from GitHub: https://github.com/BribeFromTheHive/vJass2Lua/blob/main/index.html
2) Open the HTML file in a web browser.
3) Paste in some vJass or Zinc (make sure Zinc has included the //! zinc ... //! endzinc tags - if you forgot them, just tick the box at the bottom to add them for you and paste your code in-between).
4) The vJass code is instantly converted to Lua and copied to your clipboard accordingly (no clicking required).
5) Paste the Lua script into an editor (World Editor/Text editor).
Contents

vJass2Lua - automatic script converter (Binary)

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
Updated to version 0.4 which fixes a huge number of bugs that I picked up while testing some of the largest, most popular vJass scripts. I've updated vJass-Style-Struct to support interfaces and, subsequently, updated this resource to power those interfaces.

Structs now get compiled with overloaded _ENV.

All "private" keywords are switched to "--[[p]]" because private cannot correctly be converted to local from within a struct. I can't figure out how to correctly parse in-between regex blocks "struct" and "endstruct" to make it work. I've come up with the below, which works in small scopes, but it fails in larger ones and starts leaking outside of those boundaries:

Ruby:
(?:\G(?!^)|struct)(?:(?!struct|endstruct)[\s\S])*?\Kprivate(?=[\s\S]*endstruct)

If I can figure out how to get it working, I'd like to include it in a future update.

I've found the following link to be very useful for debugging: regex101: build, test, and debug regex
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
Update to version 0.5 - private and public have been "corrected" via an update to vJass-style-struct which expands table functionality to vJass Libraries and Scopes. This means that resources that try to access public library/scope members need to change the underscore to a dot, but it otherwise works the same.

Modules now correctly handle privatization within themselves.

Libraries, scopes, modules and structs are now initialized via their dedicated functions, provided that Global Initialization is found in the map. The initialization order is identical to vJass, with the exception that they take place after the "InitGlobals" call rather than prior to it, as before.

The main things that are not currently working correctly are method operators, textmacros, and sometimes blockquotes get a bit janky. Blockquotes are easy enough to fix with any editor with syntax highlighting, but method operators and textmacros are not at all going to be a walk in the park.

Lastly, hooks are now supported and compile using the Hook API: [Lua] - Hook
 
Level 4
Joined
Oct 24, 2021
Messages
61
You can't create something that does the opposite (lua to jassYou can't create something that does the opposite (lua to jass)
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
Updated to version 0.6.0.0 - this is a huge update that finally enables method operators and enables textmacros that don't take arguments.

Method operators, like almost all the complx syntax, is made possible thanks to [Lua] - vJass-style Struct, which I updated earlier today in order to solve the problem.

Fixed the previous potential issue with blockquotes by allowing blockquotes that are deemed "safe", but killing potentially unsafe blockquotes that might be "in between" two segments of code, such as:

JASS:
library Foo requires /*
*/Lib1,/*
*/Lib2

You can't create something that does the opposite (lua to jassYou can't create something that does the opposite (lua to jass)
Although basic Lua is possible to convert, Lua actually contains far more features that vJass can never achieve. For example, [Lua] - Global Variable Remapper [The Future of GUI] is impossible with JASS.

Lua is the future, and I've developed this tool to help enable that future. I believe that vJass should only exist in order to support WarCraft 3 versions older than 1.31.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
Update to version 0.7.0.1. This is, by far, the most polished of all versions to date. I've been able to get rid of the hideous "library" and "scope" structs and replaced them with simple do/end blocks. Things work a lot more logically, now, and the presentation is much cleanear. I've changed loops to "while not" and "repeat until" wherever possible.
 
Level 23
Joined
Jun 26, 2020
Messages
1,838
Hello, have this a limit of parameters?, because I translated the common.ai and this function wasn't translated
vJASS:
function Interleave3 takes integer e1, integer m1, integer h1, integer u1, integer e2, integer m2, integer h2, integer u2, integer e3, integer m3, integer h3, integer u3 returns nothing
Edit 1: I don't know if you know, but you are keeping the keyword "code" instead of using "function".
Edit 2: I found various errors while translating the common.ai :eek:2 I will add them as long I find them, for example, in a loop if the exitwhen has a comment doesn't translate correctly:
vJASS:
function SleepUntilAtGoal takes nothing returns nothing
    loop
        exitwhen CaptainRetreating()
        exitwhen CaptainAtGoal()        // reached goal
        exitwhen CaptainIsHome()        // failed to path and returned home
        exitwhen CaptainIsEmpty()       // all units died
        call SuicideSleep(3)
    endloop
endfunction
Translated:
Lua:
function SleepUntilAtGoal()
    while not(CaptainRetreating()) do
        if CaptainAtGoal()        -- reached goal then break end
        if CaptainIsHome()        -- failed to path and returned home then break end
        if CaptainIsEmpty()       -- all units died then break end
        SuicideSleep(3)
    end
end
 
Last edited:

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
Thank you for your reply!

Yes, there is a hard limit to the number of parameters - 11. I can add another if you want.

As for comments in loops, I fixed in an unreleased version, which I’ll get to releasing in the next couple of days. There’s a couple of other problems I had identified with scoped static variables, which will be fixed in that same version.

As for “code”, I thought if you use the common.lua @Eikonium provided here: [Lua] - Debug Utils (Ingame Console etc.), that “code” and “real” are denoted as “classes” which extend “function” and “number”, but now I’m not finding their definitions.

Adding these lines to the common.lua file (or any file you anticipate having in your directory in vsCode) should fix that:

Lua:
---@class code : function
---@class real : number
 
Last edited:
Level 23
Joined
Jun 26, 2020
Messages
1,838
Hello, I found other problem, it doesn't translate good the keywords readonly static together:
vJASS:
readonly static integer Counter = 0
readonly static integer array List
readonly static integer array AbilityList

readonly static boolean ReadEnabled
Translates to:
Lua:
public.static Counter  = 0 ---@type integer
public.static List = {} ---@type integer[]
public.static AbilityList = {} ---@type integer[]

public.static boolean ReadEnabled
Other thing, how this works with the keywords constant function together?
 
Last edited:

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
Hello, I found other problem, it doesn't translate good the keywords readonly static together:
vJASS:
readonly static integer Counter = 0
readonly static integer array List
readonly static integer array AbilityList

readonly static boolean ReadEnabled
Translates to:
Lua:
public.static Counter  = 0 ---@type integer
public.static List = {} ---@type integer[]
public.static AbilityList = {} ---@type integer[]

public.static boolean ReadEnabled
Other thing, how this works with the keywords constant function together?
NPPP-UDL-XML/shortcuts.xml at master · BribeFromTheHive/NPPP-UDL-XML this is the latest version which doesn't have that issue.
 
Level 23
Joined
Jun 26, 2020
Messages
1,838
NPPP-UDL-XML/shortcuts.xml at master · BribeFromTheHive/NPPP-UDL-XML this is the latest version which doesn't have that issue.
Thank you, is more polished than before, but I tested it and still have problems with the comments in the same line in the while.
Also, the problem with the readonly static is still happening if a non array field don't have a default value, example:
vJASS:
// These translated good
readonly static integer Counter = 0
readonly static integer array List
readonly static integer array AbilityList
// This not
readonly static boolean ReadEnabled
And I think last the problem of my previous post was about having the keywords private constant function together.
And this was not good translated, I don't know what have of special, maybe the coment:
vJASS:
struct Savecode
    real digits     //logarithmic approximation
    BigNum bignum
Lua:
Savecode = Struct()
do
    local _ENV = Savecode:environment()
    local thistype, public, private = Savecode, Savecode, Savecode
    -- Here is the error
    real digits     --logarithmic approximation
    bignum = nil ---@type BigNum
And (I don't think this is your fault because there is no way to know when this happens, but I will still point this out) it doesn't consider when a real variable is used to run an event.
 
Last edited:

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
Thanks once more for your excellent feedback! All issues (outside of the real variable event) have now been fixed (tested each one) and I've increased the parameter count to 12.

I will update the documentation at a later point to add the caveat about real variables. I didn't think of that one - good point. I think these need to be prefixed with "globals.", but since JASS doesn't use that table, this would be something the user has to manually consider.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
Oh, there is something more, the system don't considers the vJass double arrays.
It does now ;)

Also supports textmacros that take arguments.

Syntax has been changed for modules.

Hooks now work with or without Hook being in the map.

Performance improvements (Version 0.8 parses Blizzard.j twice as fast as 0.7.0.3)

Bug fixes.

Textmacro tokens involving $ symbols are now formatted correctly, rather than being half-JASS, half-Lua in the worst of circumstances.

Probably a lot more. Been busy with this one.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
And (I don't think this is your fault because there is no way to know when this happens, but I will still point this out) it doesn't consider when a real variable is used to run an event.
This will be featured in a future update (still have to run tests on this). It will be part of the vJass2Lua runtime script. Thanks to Global Variable Remapper, it is now possible!

Lua:
    --Extract the globals declarations from the "globals" block so we can remap them via Global Variable Remapper to use globals.var = blah syntax.
    do
        local oldGlobals = globals
        function globals(func)
            local t = {}
            func(t)
            for key in pairs(t) do
                GlobalRemap(key, function() return globals[key] end, function(val) globals[key] = val end)
            end
            oldGlobals(func)
        end
    end

I also forgot to mention that string concatenation with "+" is now caught thanks to strings having a metatable that I was able to hook into and modify the __add method to concatenate rather than throw an error.

The list of issues that will be challenging/impossible/not worth it for vJass2Lua to cover (that I know of) are:

Integer division truncating results - all division is currently treated as a floating point. Since Lua integers are not part of a metatable, it is impossible to use the runtime script to check when integers are used for division. The best that vJass2Lua's regex could offer is to literally wrap every instance of [something] / [something] into a function call that checks the "math.type" of each argument to verify if they are integers. Imo, I flag this as "not worth it". The performance is detrimental and the user could just Ctrl+F for "/" and see for themselves what's needed.

Modules and textmacros that are meant to be run within a function (like the weird shit Nestharus and I used to do). This just won't work at all via regex nor via runtime. This sort of thing is only practical with a pre-compiler such as JassHelper that unpacks each textmacro/module and lays them with full verbosity into the script. That's not really ideal. Since Blizzard disabled the debug library, I am unable to arbitrarily access local variables between the module/macro. The only solution I have that would make these work is to literally convert any library which implements these types of modules and textmacros into a full string and concatenate them with the textmacros. This would destroy syntax highlighting and variable flagging in vsCode extensions such as that provided by Sumneko, so I'm going to rule this one as: "not worth it".

// within a string will get converted to --, even if it isn't meant to be part of a comment. Same is true for things like "this" changing to "self" within a string. Regex is powerful, but it has trouble with restricting replacements based on complicated conditions.
 
Last edited:
Level 23
Joined
Jun 26, 2020
Messages
1,838
Integer division truncating results - all division is currently treated as a floating point. Since Lua integers are not part of a metatable, it is impossible to use the runtime script to check when integers are used for division. The best that vJass2Lua's regex could offer is to literally wrap every instance of [something] / [something] into a function call that checks the "math.type" of each argument to verify if they are integers. Imo, I flag this as "not worth it". The performance is detrimental and the user could just Ctrl+F for "/" and see for themselves what's needed.
I don't see the problem, is easy to detect what values are integers in Jass and Lua has its own integer division using // instead of /
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
I don't see the problem, is easy to detect what values are integers in Jass and Lua has its own integer division using // instead of /
You over-estimate regex. When a variable is declared with a type, the best you could do with regex is to check for division on that same line. Once you step away from that, you can't just floor-divide all division which references that variable (i / 3.0 should not be floored). Defining a dictionary in regex (arguably the most complicated regex in existence) loses the ability to check for "=" and "/". The best it can do is to search for "integer" and find what word is on the right and search for that word until it reaches "endfunction" or "endlibrary" depending on whether the declaration is a global or local.

99% or more division in JASS, statistically, is using floating-point division. I would have to re-tool this entire thing and rewrite it in an .exe just to push for that <1% scenario.

I'll think about it some more. Might be I can find instances of "integer x" and change the string to "integer integer&x" (a non-vJass symbol outside of Zinc), but then how to change the value of subsequent variables references to x with the name changed? Changing it back to the original variable name is easy once everything else is done.
 
Last edited:

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
I'd like to give a sneak peek of the next version of this tool (all of the regexes will need to be re-built, but the idea is to get away from dependency on regex spam:

HTML:
<!DOCTYPE html>
<html>
    <head>
        <title>Bribe's vJass2Lua version 0.9</title>
    </head>
    <body>
        <form onsubmit="return parsevJass()">
            <input type="submit" value="Convert to Lua"/>
            <br/>
            <textarea rows="40" cols="120" id="vJass" placeholder="Enter vJass script"></textarea>
        </form>
    </body>
    <script>
        function parsevJass() {
            var vJassField = document.getElementById("vJass");
            var vJassSource = vJassField.value;
            var parsing = vJassSource;
            parsing = parsing.replace(new RegExp("^([ \\t]*)\\/\\/\\![ \\t]*novjass(.*?)^[ \\t]*\\/\\/\\![ \\t]*endnovjass", 'gms'), '$1--\[\[$2\]\]');
            parsing = parsing.replace(new RegExp("^([ \\t]*)\\/\\*(.*?)\\*\\/", 'gms'), '$1--\[\[$2\]\]');
            vJassField.value = parsing;
            return false;
        }
    </script>
</html>
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
Here's where I made it to today:

HTML:
<!DOCTYPE html>
<html>
    <head>
        <title>Bribe's vJass2Lua version 0.9</title>
    </head>
    <body>
        <form onsubmit="return parsevJass()">
            <input type="submit" value="Convert to Lua"/>
            <br/>
            <textarea rows="40" cols="120" id="vJass" placeholder="Enter vJass script"></textarea>
        </form>
    </body>
    <script>
        var recent = "";
        function parsevJass() {
            const vJassField = document.getElementById("vJass");
            const vJassSource = vJassField.value;
            var parsing = vJassSource;
            
            parsing = parsing.replace(/^([ \t]*)\/\/\![ \t]*novjass(.*?)^[ \t]*\/\/\![ \t]*endnovjass/gms, '$1--\[\[$2\]\]');
            parsing = parsing.replace(/^([ \t]*)\/\*(.*?)\*\//gms, '$1--\[\[$2\]\]');
            parsing = parsing.replace(/\/\//g, '--');
            parsing = parsing.replace(/\/\*.*?\*\//gms, ''); //delete all remaining blockquotes
            parsing = parsing.replace(/^([ \t]*)debug[ \t]+(?:set|call)*/gm, '$1--');
            parsing = parsing.replace(/^([ \t]*)(?:set|call|constant)[ \t]+/gm, '$1');
            parsing = parsing.replace(/^([ \t]*)static[ \t]+if/gm, '$1if');
            parsing = parsing.replace(/^[ \t]*native\b.*/gm, '');
            parsing = parsing.replace(/\bend\b/g, '_end');
            parsing = parsing.replace(/([^\w\d\]\)])\.([A-Za-z])/gm, '$1self\.$2');
            parsing = parsing.replace(/\.([\$\w]+)[ \t]*\(/gm, '\:$1\(');
            parsing = parsing.replace(/^([ \t]*)implement[ \t]+([\$\w]+)/gm, '$1vJass.implement\(\"$2\", SCOPE_PREFIX, thistype\)');
            
            parsing = parsing.replace(/^([ \t]*)library[ \t]+(\w+)[ \t]*(?:initializer[ \t]*(\w*))?(.*?)endlibrary/gm, '($1)do\nlocal string SCOPE_PREFIX \= \"$2_\"\n--$4_G\[\"LIBRARY_\"..SCOPE_PREFIX] = true\nif \"$3\" \~\= \"\" then OnGlobalInit\($3\) end\nend');
            parsing = parsing.replace(/^([ \t]*)loop\s+exitwhen[ \t]*(.*?)\-\-/gms, '$1while not \($2\) do \-\-');
            parsing = parsing.replace(/^([ \t]*)loop\s+exitwhen[ \t]*(.*?)$/gms, '$1while not \($2\) do');
            parsing = parsing.replace(/^([ \t]*)loop\b((?:(?!\bendloop\b|\bloop\b).)*?)^[ \t]*exitwhen([^\n\r]*)\s*?([ \t]*)endloop/gms, '$1repeat$2$4until$3');
            parsing = parsing.replace(/^([ \t]*)loop\b/gm, '$1while true do');
            parsing = parsing.replace(/^([ \t]*)exitwhen\b(.*?)\-\-/gm, '$1if$2 then break end \-\-');
            parsing = parsing.replace(/^([ \t]*)exitwhen\b(.*?)/gm, '$1if$2 then break end');
            parsing = parsing.replace(/^([ \t]*)if true then break end/gm, '$1break');
            
            parsing = parsing.replace(/^[ \t]*globals\b(.*?)\bendglobals\b/gms, function(str, globals) {
                globals = globals.replace(/^([ \t]*)private(?:[ \t]+constant)*\b/gm, '$1local');
                globals = globals.replace(/^([ \t]*)public[ \t]+constant[ \t]+(\w+)[ \t]+(\w+)([^\n\r]*)/gm, '$1local $2 $3$4\n$1_G\[SCOPE_PREFIX..\"$3\"\] \= $3');
                globals = globals.replace(/^([ \t]*)public[ \t]+(\w+)[ \t]+(\w+)([^\n\r]*)/gm, '$1local $2 $3$4\n$1GlobalRemap\(SCOPE_PREFIX..\"$3\";\, function\(\) return $3 end, function\(val\) $3 = val end\)');
                return globals;
            });
            parsing = parsing.replace(/function[ \t]*(\w+[\.]*[\w]*[ \t]*[\)\,])/, "$1");
            const macroHasArgs = /^[ \t]takes[ \t]*(.*)/m;
            const macroGetArgs = /\r?\n/;
            const macroWrapArgs = /\b\w+\b/g;
            parsing = parsing.replace(/^([ \t]*)\-\-\![ \t]*textmacro[ \t]+(\w+)(.*?)^[ \t]*\-\-\![ \t]*endtextmacro/gms, function(str, indent, name, body) {
                var statements = body.replace(macroHasArgs, "$1");
                if (statements != body) {
                    var linebreak = statements.search(macroGetArgs);
                    body = statements;
                    statements = statements.substring(0, linebreak);
                    body = body.substring(linebreak);
                    statements = statements.replace(macroWrapArgs, function(arg) { return '\"'+arg+'\"'; });
                    return 'vJass.textmacro(\"'+name+'\", {'+statements+'}, [['+body+']])';
                }
                return indent + "vJass.textmacro(\"" + name + "\", nil, function(thistype)" + body + indent + "end)";
            });
            parsing = parsing.replace(/^([ \t]*)\-\-\![ \t]*runtextmacro[ \t]+(?:optional)*[ \t]*(\w+)[ \t]*\((.*?)\)/gm, '$1vJass.runtextmacro(\"$2\", \{$3\})');
            const isNothing = /^[ \t]+nothing[ \t]+$/m;
            const getArgPairs = /([\$\w]+)[ \t]+([\$\w]+)/g;
            parsing = parsing.replace(/^([ \t]*)(.+)[ \t]+takes[ \t]+(.*)[ \t]+returns[ \t]+([\$\w]+)/gm, function(str, indent, func, params, rtype) {
                var paramEmmy = "";
                var returnEmmy = "";
                var argsResult = "";
                if (rtype != "nothing") {
                    returnEmmy = indent + "---\@return " + rtype + "\n";
                }
                if (! params.match(isNothing)) {
                    argsResult = params.replace(getArgPairs, function(str, type, name) {
                        paramEmmy += indent + "---\@param " + name + " " + type + "\n";
                        return name;
                    })
                }
                return paramEmmy + returnEmmy + indent + func + "\(" + argsResult + "\)";
            });
            
            recent = vJassSource;
            vJassField.value = parsing;
            return false;
        }
    </script>
</html>

I've only got about 40 small regexes to fit in here, so should have it caught up (and surpassing) the Notepad++ XML macro by tomorrow.

I know this isn't finished, but speed-wise, this thing is instantaneous (even on Blizzard.j).

I plan to add several configurable tickboxes to give users more control over how the code is parsed (like what is offered in cJass2Lua). Also, an "undo" button to snap it back to vJass. The tickboxes should take another couple of days, but the "undo" button I can have by tomorrow.
 
Level 8
Joined
Jul 15, 2012
Messages
143
Bribe i am dumb,
i just know gui, and little VJass,

i don't really know lua, and what is the real benefit of converting jass or vJass to Lua,
is it more faster?
or it is just to remove leak?
or there is more scope of improvement avalaible in lua?

could you give a tutorial video, that show how for beginner like me can understand the benefit of lua and how your tools work with it..

is this has anything to do with my version of world editor?
iam using jassnewgen 5d.

and is this tool required an understanding of jass?
and not intended for ordinary GUI user?

i really appreciate for the video like the one you made before for your damage engine system..it is very helpful

thanks
 
Last edited:

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
i don't really know lua, and what is the real benefit of converting jass or vJass to Lua,
Lua is a major leap in potential for programming in WarCraft 3. Do you have any other programming experience that I could use to help you to understand the conceptual differences a bit better?
is this has anything to do with my version of world editor?
iam using jassnewgen 5d.
If you are on an older version of WarCraft 3 that supports JNGP, then Lua isn't even available to use.
is it more faster?
Yes, according to benchmarks.
or it is just to remove leak?
There is no immediate benefit to using GUI backed up by Lua unless you are using a Lua library that is specifically designed to improve your GUI experience (e.g. Precise Wait / Global Variable Remapper)
or there is more scope of improvement avalaible in lua?
There is a lot more potential for Lua. Global Variable Remapper and hooking function calls are complete game-changers compared to what was possible with JASS.
could you give a tutorial video, that show how for beginner like me can understand the benefit of lua and how your tools work with it..
and is this tool required an understanding of jass?
and not intended for ordinary GUI user?
i really appreciate for the video like the one you made before for your damage engine system..it is very helpful
This tool is used to help someone to convert an existing vJass script into Lua. @Eikonium has some great tutorials for Lua development, and I have one specifically on converting vJass to Lua by hand (although it is much less developed since I wrote it before this project was started).

If you have no experience in JASS or vJass, then I would recommend simply starting with Lua. If your WarCraft 3 version is not up-to-date, then I would highly recommend getting it updated.

I will have more tutorials in the future, but right now my focus is on getting my stuff polished, and I have a lot of projects that I'm working on simultaneously at the moment.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
Version 0.9, now powered by JavaScript within a very user-friendly WebApp, is finally here. Everything was re-written, and now runs instantaneously. The source is available on GitHub (or you can just right-click the webpage and click "view source").

@TriggerHappy has introduced me to GetHub Pages, so you can now find it here: Bribe's vJass2Lua version 0.9
 
Last edited:
Level 23
Joined
Jun 26, 2020
Messages
1,838
Version 0.9, now powered by JavaScript within a very user-friendly WebApp, is finally here. Everything was re-written, and now runs instantaneously. The source is available on GitHub (or you can just right-click the webpage and click "view source").

@TriggerHappy has introduced me to GetHub Pages, so you can now find it here: Bribe's vJass2Lua version 0.9
I tested it a bit, the improvement is noticeable, but it seems it doesn't detect the keywords private function and public function together.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
I tested it a bit, the improvement is noticeable, but it seems it doesn't detect the keywords private function and public function together.
Thank you, Bribe's vJass2Lua is now updated with that fix. I have accidentally tagged that regex replacer with gm instead of gms.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
Major update to the GitHub-hosted project to bring it to version 0.A.0.0

This update brings many new features, but I'll highlight that it now also parses Zinc, fixes the issue with integer division, adds a few new UI elements to tinker with.


There are a few lingering issues with Zinc variable scoping which I intend to address within the next 24-48 hours.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
Level 19
Joined
Jan 3, 2022
Messages
320
This one breaks. I was modifying WE's generated code and wanted to convert it to Lua:
JASS:
//===========================================================================
function InitTrig_TimeOfDayTicker takes nothing returns nothing
    set gg_trg_TimeOfDayTicker = CreateTrigger(  )
    call TriggerRegisterTimerEventPeriodic( gg_trg_TimeOfDayTicker, 0.001 )
    call TriggerAddCondition( gg_trg_TimeOfDayTicker, Condition( function Trig_TimeOfDayTicker_Conditions ) )
    call TriggerAddAction( gg_trg_TimeOfDayTicker, function Trig_TimeOfDayTicker_Actions )
endfunction
Lua:
--===========================================================================
function InitTrig_TimeOfDayTicker()
    gg_trg_TimeOfDayTicker = CreateTrigger(  )
    TriggerRegisterTimerEventPeriodic( gg_trg_TimeOfDayTicker, 0.001 )
    TriggerAddCondition( gg_trg_TimeOfDayTicker, Condition( Trig_TimeOfDayTicker_Conditions ) )
    TriggerAddAction( gg_trg_TimeOfDayTicker, function Trig_TimeOfDayTicker_Actions )
end

--Conversion by vJass2Lua v0.A.1.1
The second "function" on the penultimate line is not removed

EDIT:
JASS:
//===========================================================================
//
// War3_1.32.10_timeOfDay_test
//
//   Warcraft III map script
//   Generated by the Warcraft III World Editor
//   Map Author: Luashine
//
//===========================================================================

//***************************************************************************
//*
//*  Global Variables
//*
//***************************************************************************

globals
    // User-defined
    leaderboard             udg_leaderboard            = null
    real                    udg_lastTimeOfDay          = 0
    integer                 udg_timeOfDayTickCount     = 0
    integer                 udg_secondTickCount        = 0
   
    integer control_100ms_Count=0
    integer control_20ms_Count=0
    integer control_10ms_Count=0
    integer control_5ms_Count=0
    integer control_1ms_Count=0
    integer control_0ms_Count=0
   
    integer leaderbrd_1000ms_player_id = 0
    integer leaderbrd_timeofday_player_id = 1
    integer leaderbrd_100ms_player_id = 2
    integer leaderbrd_20ms_player_id = 3
    integer leaderbrd_10ms_player_id = 4
    integer leaderbrd_5ms_player_id = 5
    integer leaderbrd_1ms_player_id = 6
    integer leaderbrd_0ms_player_id = 7

    // Generated
    trigger                 gg_trg_Melee_Initialization = null
    trigger                 gg_trg_EarlyInit           = null
    trigger                 gg_trg_TimeOfDayTicker     = null
    trigger                 gg_trg_SecondsTicker       = null
   
    trigger luashine_100ms_control_trigger = null
    trigger luashine_20ms_control_trigger = null
    trigger luashine_10ms_control_trigger = null
    trigger luashine_5ms_control_trigger = null
    trigger luashine_1ms_control_trigger = null
    trigger luashine_0ms_control_trigger = null
endglobals

function InitGlobals takes nothing returns nothing
    set udg_lastTimeOfDay = 0
    set udg_timeOfDayTickCount = 0
    set udg_secondTickCount = 0
   
    set control_100ms_Count = 0
    set control_20ms_Count = 0
    set control_10ms_Count = 0
    set control_5ms_Count = 0
    set control_1ms_Count = 0
    set control_0ms_Count = 0
endfunction

//***************************************************************************
//*
//*  Custom Script Code
//*
//***************************************************************************

//***************************************************************************
//*
//*  Triggers
//*
//***************************************************************************

//===========================================================================
// Trigger: EarlyInit
//===========================================================================
function Trig_EarlyInit_Actions takes nothing returns nothing
    call CreateLeaderboardBJ( GetPlayersAll(), "Timer Leaderboard" )
    set udg_leaderboard = GetLastCreatedLeaderboard()
    call LeaderboardAddItemBJ( Player(leaderbrd_1000ms_player_id), udg_leaderboard, "Second Count", udg_secondTickCount )
    call LeaderboardAddItemBJ( Player(leaderbrd_timeofday_player_id), udg_leaderboard, "TimeOfDay Count", udg_timeOfDayTickCount )
    call LeaderboardAddItemBJ( Player(leaderbrd_100ms_player_id), udg_leaderboard, "100ms control", control_100ms_Count )
    call LeaderboardAddItemBJ( Player(leaderbrd_20ms_player_id), udg_leaderboard, "20ms control", control_20ms_Count )
    call LeaderboardAddItemBJ( Player(leaderbrd_10ms_player_id), udg_leaderboard, "10ms control", control_10ms_Count )
    call LeaderboardAddItemBJ( Player(leaderbrd_5ms_player_id), udg_leaderboard, "5 ms control", control_5ms_Count )
    call LeaderboardAddItemBJ( Player(leaderbrd_1ms_player_id), udg_leaderboard, "1 ms control", control_1ms_Count )
    call LeaderboardAddItemBJ( Player(leaderbrd_0ms_player_id), udg_leaderboard, "0 ms control", control_0ms_Count )
endfunction

//===========================================================================
function InitTrig_EarlyInit takes nothing returns nothing
    set gg_trg_EarlyInit = CreateTrigger(  )
    call TriggerRegisterTimerEventSingle( gg_trg_EarlyInit, 0.00 )
    call TriggerAddAction( gg_trg_EarlyInit, function Trig_EarlyInit_Actions )
endfunction

//===========================================================================
// Trigger: TimeOfDayTicker
//===========================================================================
function Trig_TimeOfDayTicker_Conditions takes nothing returns boolean
    if ( not ( udg_lastTimeOfDay != GetTimeOfDay() ) ) then
        return false
    endif
    return true
endfunction

function Trig_TimeOfDayTicker_Actions takes nothing returns nothing
    set udg_lastTimeOfDay = GetTimeOfDay()
    set udg_timeOfDayTickCount = ( udg_timeOfDayTickCount + 1 )
    call LeaderboardSetPlayerItemValueBJ( Player(leaderbrd_timeofday_player_id), udg_leaderboard, udg_timeOfDayTickCount )
endfunction

//===========================================================================
function InitTrig_TimeOfDayTicker takes nothing returns nothing
    set gg_trg_TimeOfDayTicker = CreateTrigger(  )
    call TriggerRegisterTimerEventPeriodic( gg_trg_TimeOfDayTicker, 0.001 )
    call TriggerAddCondition( gg_trg_TimeOfDayTicker, Condition( function Trig_TimeOfDayTicker_Conditions ) )
    call TriggerAddAction( gg_trg_TimeOfDayTicker, function Trig_TimeOfDayTicker_Actions )
endfunction

//===========================================================================
// Trigger: SecondsTicker
//===========================================================================
function Trig_SecondsTicker_Actions takes nothing returns nothing
    set udg_secondTickCount = ( udg_secondTickCount + 1 )
    call LeaderboardSetPlayerItemValueBJ( Player(leaderbrd_1000ms_player_id), udg_leaderboard, udg_secondTickCount )
endfunction

//===========================================================================
function InitTrig_SecondsTicker takes nothing returns nothing
    set gg_trg_SecondsTicker = CreateTrigger(  )
    call TriggerRegisterTimerEventPeriodic( gg_trg_SecondsTicker, 1.00 )
    call TriggerAddAction( gg_trg_SecondsTicker, function Trig_SecondsTicker_Actions )
endfunction

// 100 ms
function luashine_100ms_control_trigger_action takes nothing returns nothing
    set control_100ms_Count = ( control_100ms_Count + 1 )
    call LeaderboardSetPlayerItemValueBJ( Player(leaderbrd_100ms_player_id), udg_leaderboard, control_100ms_Count )
endfunction
function luashine_init_trg_100ms_control takes nothing returns nothing
    set luashine_100ms_control_trigger = CreateTrigger()
    call TriggerRegisterTimerEventPeriodic( luashine_100ms_control_trigger, 0.100 )
    call TriggerAddAction( luashine_100ms_control_trigger, function luashine_100ms_control_trigger_action )
endfunction
// 20 ms
function luashine_20ms_control_trigger_action takes nothing returns nothing
    set control_20ms_Count = ( control_20ms_Count + 1 )
    call LeaderboardSetPlayerItemValueBJ( Player(leaderbrd_20ms_player_id), udg_leaderboard, control_20ms_Count )
endfunction
function luashine_init_trg_20ms_control takes nothing returns nothing
    set luashine_20ms_control_trigger = CreateTrigger()
    call TriggerRegisterTimerEventPeriodic( luashine_20ms_control_trigger, 0.020 )
    call TriggerAddAction( luashine_20ms_control_trigger, function luashine_20ms_control_trigger_action )
endfunction
// 10 ms
function luashine_10ms_control_trigger_action takes nothing returns nothing
    set control_10ms_Count = ( control_10ms_Count + 1 )
    call LeaderboardSetPlayerItemValueBJ( Player(leaderbrd_10ms_player_id), udg_leaderboard, control_10ms_Count )
endfunction
function luashine_init_trg_10ms_control takes nothing returns nothing
    set luashine_10ms_control_trigger = CreateTrigger()
    call TriggerRegisterTimerEventPeriodic( luashine_10ms_control_trigger, 0.010 )
    call TriggerAddAction( luashine_10ms_control_trigger, function luashine_10ms_control_trigger_action )
endfunction
// 5ms
function luashine_5ms_control_trigger_action takes nothing returns nothing
    set control_5ms_Count = ( control_5ms_Count + 1 )
    call LeaderboardSetPlayerItemValueBJ( Player(leaderbrd_5ms_player_id), udg_leaderboard, control_5ms_Count )
endfunction
function luashine_init_trg_5ms_control takes nothing returns nothing
    set luashine_5ms_control_trigger = CreateTrigger()
    call TriggerRegisterTimerEventPeriodic( luashine_5ms_control_trigger, 0.005 )
    call TriggerAddAction( luashine_5ms_control_trigger, function luashine_5ms_control_trigger_action )
endfunction
// 1 ms
function luashine_1ms_control_trigger_action takes nothing returns nothing
    set control_1ms_Count = ( control_1ms_Count + 1 )
    call LeaderboardSetPlayerItemValueBJ( Player(leaderbrd_1ms_player_id), udg_leaderboard, control_1ms_Count )
endfunction
function luashine_init_trg_1ms_control takes nothing returns nothing
    set luashine_1ms_control_trigger = CreateTrigger()
    call TriggerRegisterTimerEventPeriodic( luashine_1ms_control_trigger, 0.001 )
    call TriggerAddAction( luashine_1ms_control_trigger, function luashine_1ms_control_trigger_action )
endfunction
// 0 ms
function luashine_0ms_control_trigger_action takes nothing returns nothing
    set control_0ms_Count = ( control_0ms_Count + 1 )
    call LeaderboardSetPlayerItemValueBJ( Player(leaderbrd_0ms_player_id), udg_leaderboard, control_0ms_Count )
endfunction
function luashine_init_trg_0ms_control takes nothing returns nothing
    set luashine_0ms_control_trigger = CreateTrigger()
    call TriggerRegisterTimerEventPeriodic( luashine_0ms_control_trigger, 0.000 )
    call TriggerAddAction( luashine_0ms_control_trigger, function luashine_0ms_control_trigger_action )
endfunction

//===========================================================================
// Trigger: Melee Initialization
//
// Default melee game initialization for all players
//===========================================================================
function Trig_Melee_Initialization_Actions takes nothing returns nothing
    call MeleeStartingVisibility(  )
    call MeleeStartingHeroLimit(  )
    call MeleeGrantHeroItems(  )
    call MeleeStartingResources(  )
    call MeleeClearExcessUnits(  )
    call MeleeStartingUnits(  )
endfunction

//===========================================================================
function InitTrig_Melee_Initialization takes nothing returns nothing
    set gg_trg_Melee_Initialization = CreateTrigger(  )
    call TriggerAddAction( gg_trg_Melee_Initialization, function Trig_Melee_Initialization_Actions )
endfunction

//===========================================================================
function InitCustomTriggers takes nothing returns nothing
    call InitTrig_EarlyInit(  )
    call InitTrig_TimeOfDayTicker(  )
    call InitTrig_SecondsTicker(  )
    call InitTrig_Melee_Initialization(  )
    // my triggers
    call luashine_init_trg_100ms_control()
    call luashine_init_trg_20ms_control()
    call luashine_init_trg_10ms_control()
    call luashine_init_trg_5ms_control()
    call luashine_init_trg_1ms_control()
    call luashine_init_trg_0ms_control()
endfunction

//===========================================================================
function RunInitializationTriggers takes nothing returns nothing
    call ConditionalTriggerExecute( gg_trg_Melee_Initialization )
endfunction

//***************************************************************************
//*
//*  Players
//*
//***************************************************************************

function InitCustomPlayerSlots takes nothing returns nothing

    // Player 0
    call SetPlayerStartLocation( Player(0), 0 )
    call SetPlayerColor( Player(0), ConvertPlayerColor(0) )
    call SetPlayerRacePreference( Player(0), RACE_PREF_HUMAN )
    call SetPlayerRaceSelectable( Player(0), true )
    call SetPlayerController( Player(0), MAP_CONTROL_USER )

endfunction

function InitCustomTeams takes nothing returns nothing
    // Force: TRIGSTR_010
    call SetPlayerTeam( Player(0), 0 )

endfunction

//***************************************************************************
//*
//*  Main Initialization
//*
//***************************************************************************

//===========================================================================
function main takes nothing returns nothing
    call SetCameraBounds( -3328.0 + GetCameraMargin(CAMERA_MARGIN_LEFT), -3584.0 + GetCameraMargin(CAMERA_MARGIN_BOTTOM), 3328.0 - GetCameraMargin(CAMERA_MARGIN_RIGHT), 3072.0 - GetCameraMargin(CAMERA_MARGIN_TOP), -3328.0 + GetCameraMargin(CAMERA_MARGIN_LEFT), 3072.0 - GetCameraMargin(CAMERA_MARGIN_TOP), 3328.0 - GetCameraMargin(CAMERA_MARGIN_RIGHT), -3584.0 + GetCameraMargin(CAMERA_MARGIN_BOTTOM) )
    call SetDayNightModels( "Environment\\DNC\\DNCLordaeron\\DNCLordaeronTerrain\\DNCLordaeronTerrain.mdl", "Environment\\DNC\\DNCLordaeron\\DNCLordaeronUnit\\DNCLordaeronUnit.mdl" )
    // 1.32.10: call NewSoundEnvironment( "Default" )
    call SetAmbientDaySound( "LordaeronSummerDay" )
    call SetAmbientNightSound( "LordaeronSummerNight" )
    call SetMapMusic( "Music", true, 0 )
    call InitBlizzard(  )
    call InitGlobals(  )
    call InitCustomTriggers(  )
    call RunInitializationTriggers(  )

endfunction

//***************************************************************************
//*
//*  Map Configuration
//*
//***************************************************************************

function config takes nothing returns nothing
    call SetMapName( "TimeOfDay Test" )
    call SetMapDescription( "ROC v1.0 compatible" )
    call SetPlayers( 1 )
    call SetTeams( 1 )
    call SetGamePlacement( MAP_PLACEMENT_USE_MAP_SETTINGS )

    call DefineStartLocation( 0, -64.0, 64.0 )

    // Player setup
    call InitCustomPlayerSlots(  )
    call SetPlayerSlotAvailable( Player(0), MAP_CONTROL_USER )
    call InitGenericPlayerSlots(  )
endfunction
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
Thank you for testing this, @Luashine ! This has been fixed in the latest update (0.A.1.2). This particular issue was caused by a missing "g" flag on the regex which looks up that part of the code.

I also stumbled across the fact that public/private constant functions were not processed correctly. This has been addressed as well.
 
Level 9
Joined
Oct 19, 2014
Messages
94
the converter has issues with FourCC codes from Jass, example:
call SaveInteger(Hashtable,'CODE','COD1',Value)
becomes a mess, sometimes FourCC taking rest of the function values into itself, inserting ) into the code, without FourCC, becoming undefiniedValue
example:
SaveInteger(Hashtable,FourCC('CODE',')COD1',Value)
SaveInteger(Hashtable,undefinedPID,0,Value)
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
the converter has issues with FourCC codes from Jass, example:
call SaveInteger(Hashtable,'CODE','COD1',Value)
becomes a mess, sometimes FourCC taking rest of the function values into itself, inserting ) into the code, without FourCC, becoming undefiniedValue
example:
SaveInteger(Hashtable,FourCC('CODE',')COD1',Value)
SaveInteger(Hashtable,undefinedPID,0,Value)
Thanks again for the report. The issue is now hotfixed here: Bribe's vJass2Lua version 0.A.2.1

Just as an FYI, I've also migrated this hotfix into the unreleased version I've been working on, which is either going to be 0.B or 0.A.3, depending on what comes out of it.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
could it be possible to add optional flag to replace
Code:
exitwhen
with
Code:
while(not())
loop instead of repeat ... untill
In most cases, it works, but it changes the behavior of the first loop to do so. In some cases a user might want to loop once even if "until"'s condition is already met.

Currently, the repeat...until loop is used only if an exitwhen statement is found immediately before the endloop block.

Is there a reason you want the "while not" format? Is it just for loop format consistency?
 
Level 9
Joined
Oct 19, 2014
Messages
94
In most cases, it works, but it changes the behavior of the first loop to do so. In some cases a user might want to loop once even if "until"'s condition is already met.

Currently, the repeat...until loop is used only if an exitwhen statement is found immediately before the endloop block.

Is there a reason you want the "while not" format? Is it just for loop format consistency?
tried converting jass to lua then lua to typescript, but ltts (lua-to-typescript) did not support repeat ... untill
optionaly it could be transformed into
Code:
while(true)
do





if(bool) then break end end
 
Last edited:

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
any vjass I try converting always fails since it adds those hidden calls.
Your map is still set to JASS, it seems. This guide shows how to get started with getting your actual map to read Lua: Transitioning from GUI to Lua/JASS

Once the map is set to Lua, save and exit the map. Then, reload the map and it will allow you to create a custom script within the trigger editor. That's what you paste Lua code into.
 
Your map is still set to JASS, it seems. This guide shows how to get started with getting your actual map to read Lua: Transitioning from GUI to Lua/JASS

Once the map is set to Lua, save and exit the map. Then, reload the map and it will allow you to create a custom script within the trigger editor. That's what you paste Lua code into.
Does it need to be a fresh empty map?
 

Attachments

  • DungeonGenerator.w3x
    410.9 KB · Views: 13

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
Here, I have fixed the file.

Could you please provide me with the original vJass text for "DungeonTest"? I need to debug that script to find out why it is failing. To me, it seems like it grabbed some of the code, cached it as a string or comment, then re-inserted it unprocessed.
 

Attachments

  • DungeonGenerator.w3x
    405.3 KB · Views: 14
Here, I have fixed the file.

Could you please provide me with the original vJass text for "DungeonTest"? I need to debug that script to find out why it is failing. To me, it seems like it grabbed some of the code, cached it as a string or comment, then re-inserted it unprocessed.
Oh I see what went wrong, it's custom script literally not trigger... Pretty sure this is user error on my end as I just pasted the vjass into the converter then back into the converted triggers as lua.

Re-reading your post got me thinking there's a way to fully convert a map instead of one trigger/script at a time?

Also trying it out in-game and even though the command registers it doesn't run any of the other code to generate dungeons/caverns, recently learnt one has to call lua into a gui trigger but I don't see how too with this vjass-translated map.

Original vjass - Dungeon Generator & Stamp
 
Level 19
Joined
Jan 3, 2022
Messages
320
Bug report: A native declaration in Jass (seems to be ok?) is converted into an invalid declaration in Lua. I think it should just make an error and not convert.
JASS:
constant native GetIssuedOrderId takes nothing returns integer
Lua:
native GetIssuedOrderId()
Edit following that, the next line failed to convert:
JASS:
constant native GetIssuedOrderId takes nothing returns integer
function Debug_message takes string Text returns nothing

    call DisplayTextToPlayer(Player(0), 0, 0, Text)
    set Text=null
endfunction
Lua:
function Debug_message takes string Text returns nothing

    DisplayTextToPlayer(Player(0), 0, 0, Text)
    Text=nil
end
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
Bug report: A native declaration in Jass (seems to be ok?) is converted into an invalid declaration in Lua. I think it should just make an error and not convert.
JASS:
constant native GetIssuedOrderId takes nothing returns integer
Lua:
native GetIssuedOrderId()
Edit following that, the next line failed to convert:
JASS:
constant native GetIssuedOrderId takes nothing returns integer
function Debug_message takes string Text returns nothing

    call DisplayTextToPlayer(Player(0), 0, 0, Text)
    set Text=null
endfunction
Lua:
function Debug_message takes string Text returns nothing

    DisplayTextToPlayer(Player(0), 0, 0, Text)
    Text=nil
end
I'll have a look into this next week, but thank you for reporting this! At one point, I just deleted all natives, because they already exist in _G. Not sure what I ended up doing for the current release.

Can you please confirm if this was on the GitHub site, or on the download on this page? Because the download doesn't include hotfixes.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
Is converting entire map scripts to lua supported and does lua offer any speed benefits being directly converted from jass without any modifications to the script?
I don't currently have a way to do that, but I have future plans to allow a .wtg file to be parsed. It doesn't convert the map, but it would wash over the exported triggers to get them all Lua-fied. If given 2-3 weeks to work on just that on my free time, I can manage. But I have other projects, plus God of War 5 just came out.

I have never run any benchmarks on how quickly Lua runs versus how JASS runs, when trying to compute the same data. I used to buy into an idea of "Lua Fast Triggers" which replaced normaly trigger evaluate/execute in Lua with function calls, but someone brought to my attention that the overhead of those functions is lighter than it used to be.

The main reason to use Lua is for stuff like hooks (PreciseWait, Global Variable Remapper, Event, Action) and for forwards-compatibility with innovations that have yet to take off because the community at large has struggled to switch. Lua has so much untapped potential.
 
Top