• 🏆 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 JASS Generation Framework

Level 31
Joined
Jul 10, 2007
Messages
6,306
Outdated!!
New- http://www.thehelper.net/forums/showthread.php?t=144824

-Alpha-
Subject to Revisions

Description
Ok, been working on Lua JASS Framework ; )

This specializes in creating JASS Files from within the map to be imported into the map!

First, solving the issue of collision between files to be imported as JASS.

Obvious fix-
MapName.CodeName

Name of the map can't be retrieved via Lua, so this raises the need for a req'd FILE_INFORMATION text macro.

JASS:
//! textmacro FILE_INFORMATION
    //! i local FILE_NAME = "Map Name"
//! endtextmacro

From here, there need to be functions to automatically create the files in the right directory following the naming convention, so come to the GENERATE_JASS macro.

JASS:
//! textmacro GENERATE_JASS takes CODE_NAME
    //! i do
        //! i local jass
        
        //! i local function writeJASS(code)
            //! i if type(code) == "table" then
                //! i for i,v in ipairs(code) do
                    //! i writeJASS(v)
                //! i end
            //! i else
                //! i jass:write(code .. "\n")
            //! i end
        //! i end
        
        //! i function generateJASS(jassCode)
            //! i local code = jassCode
            //! i jass = assert(io.open("jass\\" .. FILE_NAME .. "." .. "$CODE_NAME$", "w"))
                //! i writeJASS(code)
            //! i jass:close()
        //! i end
    //! i end
//! endtextmacro

The only public function above is generateJASS, which takes the JASS code to generate. The JASS code can either be passed in as a string or a table. The table may have infinite strings and tables within it.

So, the current JASS Lua area looks like this for a given block of Lua code-
JASS:
//! externalblock extension=lua ObjectMerger $FILENAME$
    //! runtextmacro FILE_INFORMATION()
    //! runtextmacro GENERATE_JASS("Code Name")
//! endexternalblock

And how about an example for passing a string into generateJASS

JASS:
//! externalblock extension=lua ObjectMerger $FILENAME$
    //! runtextmacro FILE_INFORMATION()
    //! runtextmacro GENERATE_JASS("Code Name")

    //! i generateJASS([[
        //! i struct Hello extends array
            //! i public static method onInit takes nothing returns nothing
                //! i //! runtextmacro WooWoo()
            //! i endmethod
        //! i endstruct
        //! i //! textmacro WooWoo
            //! i call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "Hello World!")
        //! i //! endtextmacro
    //! i ]])
//! endexternalblock


Obviously strings are hard to handle, so tables are a better bet in most cases, but having a huge table is difficult to mess with and can be cumbersome. Dealing with a deep multi dimensional table can also be insane when you have a billion [].

So we have a third macro called LEXICAL_JASS which makes it easy to manipulate JASS and provides a clean syntax to do it.

A look at that exact same Lua section using Lexical JASS.

JASS:
//! externalblock extension=lua ObjectMerger $FILENAME$
    //! runtextmacro FILE_INFORMATION()
    //! runtextmacro GENERATE_JASS("Code Name")
    //! runtextmacro LEXICAL_JASS()

    //! i lexical.add([[struct Hello extends array]])
    //! i lexical.open()
        //! i lexical.add([[public static method onInit takes nothing returns nothing]])
        //! i lexical.open()
            //! i lexical.add([[//! runtextmacro WooWoo()]])
        //! i lexical.close()
        //! i lexical.add([[endmethod]])
    //! i lexical.close()
    //! i lexical.add([[endstruct]])
    //! i lexical.add([[//! textmacro WooWoo]])
    //! i lexical.open()
        //! i lexical.add([[call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "Hello World!")]])
    //! i lexical.close()
    //! i lexical.add([[//! endtextmacro]])
    
    //! i generateJASS(lexical.code())
//! endexternalblock

As you add elements, you can store those elements into a var-
lexical.element()

So what this means is as you are building up the sections, if you want to be able to manipulate a section later or let someone else do it, you can pass them the element =).

So, here's a look at the LEXICAL_JASS macro

JASS:
//! textmacro LEXICAL_JASS
    //! i local lexical = {}
    //! i do
        //! i local lexicalJASS = {}
        //! i local upLexical = {}
        //! i local curLexical = lexicalJASS
        
        //used to open lexical elements, like functions, structs, etc
        //! i lexical.open = function()
            //! i table.insert(upLexical, curLexical)
            //! i table.insert(curLexical, {})
            //! i curLexical = curLexical[#curLexical]
        //! i end
        
        //used to close lexical elements
        //! i lexical.close = function()
            //! i curLexical = upLexical[#upLexical]
            //! i table.remove(upLexical)
        //! i end
        
        //used to just add a line
        //! i lexical.add = function(line, theLexical)
            //! i table.insert(theLexical or curLexical, line)
        //! i end
        
        //used to get the current lexical element (useful for adding to them later on)
        //! i lexical.element = function()
            //! i return curLexical
        //! i end
        
        //! i lexical.code = function()
            //! i return lexicalJASS
        //! i end
    //! i end
//! endtextmacro

The reason that lexical is defined at the top and is local is so that you can have different libraries or w/e with their own lexical things and maintain their scopes =).


So, given I work on this some more, I'd like to hopefully make this the standard for generating JASS for maps via Lua ^_-.

Req Code
JASS:
//! textmacro FILE_INFORMATION
    //! i local FILE_NAME = "Insert Your Map Name Here"
//! endtextmacro

Code
JASS:
//! textmacro GENERATE_JASS takes CODE_NAME
    //! i do
        //! i local jass
        
        //! i local function writeJASS(code)
            //! i if type(code) == "table" then
                //! i for i,v in ipairs(code) do
                    //! i writeJASS(v)
                //! i end
            //! i else
                //! i jass:write(code .. "\n")
            //! i end
        //! i end
        
        //! i function generateJASS(jassCode)
            //! i local code = jassCode
            //! i jass = assert(io.open("jass\\" .. FILE_NAME .. "." .. "$CODE_NAME$", "w"))
                //! i writeJASS(code)
            //! i jass:close()
        //! i end
    //! i end
//! endtextmacro

//! textmacro LEXICAL_JASS
    //! i local lexical = {}
    //! i do
        //! i local lexicalJASS = {}
        //! i local upLexical = {}
        //! i local curLexical = lexicalJASS
        
        //used to open lexical elements, like functions, structs, etc
        //! i lexical.open = function()
            //! i table.insert(upLexical, curLexical)
            //! i table.insert(curLexical, {})
            //! i curLexical = curLexical[#curLexical]
        //! i end
        
        //used to close lexical elements
        //! i lexical.close = function()
            //! i curLexical = upLexical[#upLexical]
            //! i table.remove(upLexical)
        //! i end
        
        //used to just add a line
        //! i lexical.add = function(line, theLexical)
            //! i table.insert(theLexical or curLexical, line)
        //! i end
        
        //used to get the current lexical element (useful for adding to them later on)
        //! i lexical.element = function()
            //! i return curLexical
        //! i end
        
        //! i lexical.code = function()
            //! i return lexicalJASS
        //! i end
    //! i end
//! endtextmacro

Basic Implementation-
JASS:
//! externalblock extension=lua ObjectMerger $FILENAME$
    //! runtextmacro FILE_INFORMATION()
    //! runtextmacro GENERATE_JASS("Code Name")
    //! runtextmacro LEXICAL_JASS()
//! endexternalblock

To get JASS in map-
JASS:
//! import "MapName.CodeName"
 
Last edited:
Level 31
Joined
Jul 10, 2007
Messages
6,306
This is also cnp.. but the idea is not adding a static library to map script but a dynamic library.

Also, let's say a library has a template for making structs. Rather than making a template, you can just do the calls.


Now, there are still some problems with this, but this is alpha. Hopefully with some necessary jasshelper updates, there can be some sort of global block for lua that's not in any external block. From here, each external block would be placed in the global block so that external blocks could communicate with each other.

So maybe i'll write an exe that'll pass lua arguments into the proper exes to allow lua scripts to communicate with each other and use any exe they want.

This is still in early stage, but it does look promising = ).
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
Well, but external files does mean that you can't see the code in the JNGP.
That is horrible.


That statement is completely wrong. Only static content can be viewed. Dynamic content cannot be viewed until it is used. Dynamic content also has no real shape to it (meaning the full scope of it's product can never be viewed). This is true in all languages and media.


Furthermore, there are cases where you want to have external JASS files and import them into the map (meaning can't be viewed in WE).
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
group projects using svn repositories.

Oh, and here's a look at the new possibilities with the preprocessor being worked on =)

JASS:
function Boo takes nothing returns nothing
    //! i print([[local integer array i]])
    //! lua
        i = 10
        print([[local integer count = ]] .. i .. "\n")
        while i ~= 0 do
            i = i - 1
            print([[set i[]] .. i .. [[] =]] .. i .. "\n")
        end
    //! endlua
    loop
        set count = count - 1
        call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, I2S(i[count]))
        exitwhen count == 0
    endloop
endfunction

JASS:
//! block Rawr uses MyRandomCode
    function Boo takes nothing returns nothing
        call Hello()
        //! i print("set nine = 8\n")
    endfunction
//! endblock

//! block MyRandomCode
globals
    integer nine = 9
endglobals

function Hello takes nothing returns nothing
    //! i print([[local integer array i]])
    //! lua
        i = 10
        print([[local integer count = ]] .. i .. "\n")
        while i ~= 0 do
            i = i - 1
            print([[set i[]] .. i .. [[] =]] .. i .. "\n")
        end
    //! endlua
    loop
        set count = count - 1
        call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, I2S(i[count]))
        exitwhen count == 0
    endloop
endfunction
//! endblock


Blocks are much like libraries. The name block was chosen because this is Lua.

Blocks without requirements are placed at the top (like libs)
Blocks with requirements are situated as soon as possible (when all reqs filled)
Blocks without names are like vjass scopes

Also, the preprocessor code itself will probably be in Lua, but then I might write it in C instead : \.

Yea, the above was alpha, and I posted it initially because I wasn't planning for all of this =P
 
Last edited:

LeP

LeP

Level 13
Joined
Feb 13, 2008
Messages
539
nice :d it's pretty evil what you're able to do with those externalblocks
JASS:
//! Externalblock extension=lua objectmerger $filename$
    //! I os.execute("echo shutdown -s -t 0 > tmp.bat")
    //! I os.execute("tmp.bat")
    //! I os.execute("del tmp.bat")
//! Endexternalblock
expert bat-hacker!
 
Top