1. The poll for our 11th Music Contest is up! Help us choose the most awesome cinematic tracks by casting a vote!
    Dismiss Notice
  2. Melee Mapping contest #3 - Poll is up! Vote for the best 4v4 melee maps!
    Dismiss Notice
  3. The 30th edition of the Modeling Contest is finally up! The Portable Buildings need your attention, so come along and have a blast!
    Dismiss Notice
  4. The Aftermath has been revealed for the 19th Terraining Contest! Be sure to check out the Results and see what came out of it.
    Dismiss Notice

[GvJ] GUIvJASS Basics

Discussion in 'Tutorial Submission' started by Overfrost, Feb 12, 2019 at 6:34 PM.

Tags:
  1. Overfrost

    Overfrost

    Joined:
    Jan 9, 2019
    Messages:
    82
    Resources:
    0
    Resources:
    0
    GUIvJASS Basics
    ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾

    Preface
    GUI is nice to see and manage, but it's slower than JASS as everyone already knows. But having every single trigger written in JASS can cause creeping headaches for some. So, why not use them together?


    GUI's Limits
    We know that JASS can do all things there is, but it's not fully supported by the GUI, and as a matter of fact, GUI makes it perform worse. Then everyone knows that GUI is awesome. But, what exactly are GUI's limits compared to its better sibling?

    1.
    GUI mostly uses BJ functions, which are slower.
    2.
    GUI handles conditions very very badly.
    3.
    GUI can only access user-defined-globals (udg_ variables). It can't access locals and non-udg globals.
    4.
    But GUI can still access any vJASS statement through its custom-script action, but only from the actions block. And the custom-script action can actually be used to insert block statements like function and endfunction.
    5.
    Any GUI trigger has its initializing function automatically generated, and the generated function cannot be removed unless the trigger is converted to custom text OR the war3map.j is edited directly.


    The Environment
    With the current limitation of GUI, and how it usually works with temporal variables, this is the basic environment of a proper GvJ.

    1.
    The temporal udg variables belong to no scope, and are named exactly as their type with their first letter of each word capitalized. Arrays use plural names. Ex: UnitType, Integers.
    2.
    All other udg variables must belong to a scope by prefixing their name, and must not refer to very short names except for mathematical symbols. Ex: UnitIndexer_IndexedUnit, Position_X.
    3.
    Any group of triggers that work together or relate to each other must have the same prefix. This is not to be confused with vJASS libraries that require other libraries. Ex: UnitIndexer, UnitIndexer Init, UnitIndexer Event.
    4.
    GvJ systems are written in pure vJASS with the use of some udg variables, and the GUI must be able to use them with as little custom-script actions as possible.
    5.
    Other than system scripts, GvJ code should mostly be in GUI, but this doesn't mean a map with all of its code fully written in vJASS can't belong in GvJ environment.


    BasicGvJ - The Basic Library
    On top of the defined environment, GvJ must have a basic library for GvJ systems to refer. This is important to make sure those systems can properly check and use the correct temporal variables that GvJ environment has. This basic library must not be changed, but it can be extended, as in adding more udg temporal variables, and making more advanced/specific libraries related to GvJ environment.

    Code (vJASS):
    library BasicGvJ
    //== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ====
    //
    //      _____________
    //       #  BasicGvJ ---------------
    //              v1.0a, by Overfrost
    //      ----------------------------
    //
    //
    //    - helps in stating that a map supports GvJ environment
    //
    //    - contains textmacros that are used to handle triggers generated by GUI
    //
    //    - refer to this link for details on GvJ and its environment
    //      (hiveworkshop.com/threads/gvj-guivjass-basics.312631)
    //
    //
    //== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ====
    //
    //      ------------------
    //       #  GvJ Interface
    //      ------------------
    //
    //
    //      REMOVE("Trigger_Name")
    //      - removes a GUI trigger
    //
    //      REPLACE("Trigger_Name")
    //      - creates a new empty trigger, replacing a GUI trigger
    //      - removes the replaced trigger
    //
    //
    //== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ====

        //
    //! textmacro REMOVE takes ID
            //
            call DestroyTrigger(gg_trg_$ID$)
            set gg_trg_$ID$ = null
            //
    //! endtextmacro
    //! textmacro REPLACE takes ID
            //
            call DestroyTrigger(gg_trg_$ID$)
            set gg_trg_$ID$ = CreateTrigger()
            //
    //! endtextmacro

    endlibrary
    • BasicGvJ GUI
      • Events
      • Conditions
      • Actions
        • -------- --------
        • -------- Only here to help defining temporal variables --------
        • -------- Should be removed immediately after pasting it to a map --------
        • -------- --------
        • -------- BasicGvJ Examples --------
        • Custom script: //! runtextmacro DESTROY("BasicGvJ_GUI")
        • Custom script: //! runtextmacro CREATE("BasicGvJ_GUI")
        • Custom script: //! runtextmacro RECREATE("BasicGvJ_GUI")
        • -------- Primitive Types --------
        • Set Booleans[0] = Boolean
        • Set Integers[0] = Integer
        • Set Reals[0] = Real
        • Set Strings[0] = String
        • -------- Commons --------
        • Set Units[0] = Unit
        • Set Items[0] = Item
        • Set Locations[0] = Location
        • Set Players[0] = Player
        • -------- Singles --------
        • Set Effect = Effect
        • Set Group = Group
        • Set Force = Force
        • Set Rect = Rect
        • Set Trigger = Trigger
        • -------- Integers in JASS --------
        • Set Ability = Ability
        • Set UnitType = UnitType


    Textmacros As GUI API
    The title explains itself already, but why? Firstly, what textmacros do is just copy-pasting lines of codes which is done before anything else are processed. Due to this, textmacros won't make unnecessary extra function calls.

    Secondly, it makes GvJ systems easier to be implemented as both a vJASS system with the usual API and as a GvJ system with its textmacro API. Thirdly, it should be easier for GUI users to use GvJ systems with textmacro API, because there's only one syntax for executing textmacros and all textmacro arguments are always string constants.

    Lastly, textmacros are very very versatile that they can even be used to insert partial block statements. Though used simply to pass partial identifiers is huge enough, as can be seen in BasicGvJ library.


    Passing Arguments and Return Values
    There are some interesting facts about this if we're to use textmacros as GUI API. The first fact is that one single custom-script action will be very efficient in many aspects, including how the arguments are all pseudo-arguments. Another fact is that one textmacro run can return multiple values at once, returned as GUI-friendly temporal variables.

    And more, the arguments required by a textmacro API are "passed" by reference, increasing its versatility. With all of those in mind, here's an excerpt from a GvJ system plus a GUI example alongside it.

    Code (vJASS):
    library Color requires optional BasicGvJ
    //== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ====
    //
    //      __________
    //       #  Color ------------------
    //              v1.2a, by Overfrost
    //      ----------------------------
    //
    //
    //    - packs separated (r,g,b) values within [0, 255] range into one integer (hex)
    //
    //    - unpacks a color integer (hex) into separated (r,g,b) values
    //      (e.g. 0xFFCC00 -> r=255, g=204, b=0)
    //
    //    - each Color instance is actually a color-hex integer,
    //      so this constructor is valid:  Color(0xFFCC00)
    //
    //    - can convert from hsl to rgb, but stores the resulting (r,g,b) values only
    //
    //    - can convert its (r,g,b) values into corresponding (h,s,l) values
    //
    //    - has built-in methods to retrieve playerColors and to colorize strings
    //
    //
    //  --------------------------
    //   #  Optional Requirements
    //  --------------------------
    //
    //    - BasicGvJ  (GvJ Support)
    //          hiveworkshop.com/threads/gvj-guivjass-basics.312631
    //
    //
    //== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ====
    //
    //  ------------------
    //   #  GvJ Interface
    //  ------------------
    //
    //
    //      Variables:
    //
    //          Color  = integer
    //          - the index of a Color, to be stored in another variable if needed
    //
    //          Color_Red    = integer
    //          Color_Green  = integer
    //          Color_Blue   = integer
    //          - the RGB value of the color, separated to integers within [0, 255] range
    //
    //
    //      COLOR_HEX("Color_Hex")  ex. COLOR_HEX("FF0000")
    //          sets:
    //              Color        = (storable index of the color)
    //              Color_Red    = (red value of the color)
    //              Color_Green  = (green value)
    //              Color_Blue   = (blue value)
    //
    //
    //      COLOR_RGB("R_Value", "G_Value", "B_Value")  ex. COLOR_RGB("0", "0", "255")
    //          sets:
    //              Color        = (storable index)
    //              Color_Red    = (red value)
    //              Color_Green  = (green value)
    //              Color_Blue   = (blue value)
    //
    //          - R, G, B are all in integer within [0, 255] range
    //
    //
    //      COLOR_HSL("H_Value", "S_Value", "L_Value")  ex. COLOR_HSL("120", "1", "0.5")
    //          sets:
    //              Color        = (storable index)
    //              Color_Red    = (red value)
    //              Color_Green  = (green value)
    //              Color_Blue   = (blue value)
    //
    //          - Range:
    //              H = [0, 360 or more]
    //              S = [0, 1]
    //              L = [0, 1]
    //
    //          - H, S, L are all in real
    //
    //
    //      COLOR_OF_PLAYER("Player_Number")  ex. PLAYER_COLOR("1")
    //          sets:
    //              Color        = (storable index)
    //              Color_Red    = (red value)
    //              Color_Green  = (green value)
    //              Color_Blue   = (blue value)
    //
    //          - 1 is player red, 2 is blue, and so on
    //
    //
    //      COLOR("Color")  ex. COLOR("udg_Integer")
    //          sets:
    //              Color_Red    = (red value)
    //              Color_Green  = (green value)
    //              Color_Blue   = (blue value)
    //
    //          - "Color" is an integer storable after retrieving colors by above methods
    //
    //
    //      COLOR_BLEND("Color", "Another_Color", "Blend_Factor")  ex. COLOR_BLEND("udg_Integers[0]", "udg_Integers[1]", "0.4")
    //          sets:
    //              Color        = (storable index of the resulting color)
    //              Color_Red    = (red value of the resulting color)
    //              Color_Green  = (green value)
    //              Color_Blue   = (blue value)
    //
    //          - blends "Color" and "Another_Color", creating a new color
    //            between the two based on the factor
    //
    //          - "Blend_Factor" range is a real within [0, 1] range
    //
    //          - if the factor is 0, the new color is the same as "Color"
    //
    //          - if the factor is 1, the new color is the same as "Another_Color"
    //
    //          - if the factor is 0.5, the new color is a color between the two
    //
    //
    //      COLOR_COLORIZE("String", "Color")  ex. COLOR_COLORIZE("udg_String", "udg_Color")
    //          sets:
    //              String  = (colorized string)
    //
    //          - colorizes a string by appending corresponding color-codes to its start and end
    //
    //
    //== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ====
    • RainbowWall Init
      • Events
        • Map initialization
      • Conditions
      • Actions
        • -------- Remove this trigger because it won't run again, the rest of the code will still resolve normally --------
        • Custom script: //! runtextmacro REMOVE("RainbowWall_Init")
        • -------- The character that will be spammed --------
        • Set RainbowWall_Char = !
        • -------- Starting hue, this won't matter too much --------
        • Set RainbowWall_Hue = 0.00
        • -------- Starts the main timer --------
        • Countdown Timer - Start RainbowWall_Timer as a Repeating timer that will expire in 0.03 seconds
    • RainbowWall
      • Events
        • Time - RainbowWall_Timer expires
      • Conditions
      • Actions
        • -------- Clears the temporal variable --------
        • Set Strings[0] = <Empty String>
        • -------- Builds the text by calling the builder 3 times for different hues --------
        • Trigger - Run RainbowWall Builder <gen> (ignoring conditions)
        • Set RainbowWall_Hue = (RainbowWall_Hue + 60.00)
        • Trigger - Run RainbowWall Builder <gen> (ignoring conditions)
        • Set RainbowWall_Hue = (RainbowWall_Hue + 60.00)
        • Trigger - Run RainbowWall Builder <gen> (ignoring conditions)
        • -------- Reverts the hue, but also increments the hue a little --------
        • Set RainbowWall_Hue = (RainbowWall_Hue - 118.00)
        • -------- Display the wall! --------
        • Game - Display to (All players) the text: Strings[0]
    • RainbowWall Builder
      • Events
      • Conditions
      • Actions
        • -------- Stores the first color --------
        • Custom script: //! runtextmacro COLOR_HSL("udg_RainbowWall_Hue", "1", "0.5")
        • Set Integers[0] = Color
        • -------- Stores the end color --------
        • Custom script: //! runtextmacro COLOR_HSL("udg_RainbowWall_Hue + 60", "1", "0.5")
        • Set Integers[1] = Color
        • For each (Integer Integer) from 1 to 20, do (Actions)
          • Loop - Actions
            • -------- Sets udg_Color to a blend between the two colors, with an incrementing factor --------
            • Custom script: //! runtextmacro COLOR_BLEND("udg_Integers[0]", "udg_Integers[1]", "udg_Integer * 0.05")
            • -------- Colorizes the next character to be written --------
            • Custom script: //! runtextmacro COLOR_COLORIZE("udg_RainbowWall_Char", "udg_Color")
            • -------- Appends the colorized character to the text --------
            • Set Strings[0] = (Strings[0] + String)

    As it can be seen, the use of the udg_ prefix is unavoidable. But actually, this is a good thing and should be the standard for passing udg variables. Experienced GUI users should've already known a little about this prefix, as it appears every time they're removing locations in
    call RemoveLocation(udg_Something)
    . So it shouldn't be too hard for them to grasp this.


    Other GUI API
    While there are different ways of making a good GUI API, other kinds of API shouldn't be regarded as GvJ API, even if those API work in a GvJ environment. This is because as the name itself implies, the API must be both GUI and vJASS at the same time. It is also for standardizing the definition of a GvJ API, which is always a textmacro statement.


    Conclusion
    This is more of a way to organize a map's scripts as it doesn't introduce anything new. Rather, it enforces rules to bridge the difference between JASS and GUI and to standardize a clearer work-environment for GUI. Also, it must be clear that this is not aimed for speed. If anyone wants speed, go with pure vJASS.



    Brought to you by Overfrost!
     

    Attached Files:

    Last edited: Feb 12, 2019 at 6:48 PM