1. This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn More.
  2. The member Kam is making HIVE coasters. Take a look. For every coaster you buy, Hive gets $1.
    Dismiss Notice
  3. Buy it, use it, break it, fix it, trash it, change it, mail - upgrade it. Join (Optionally) Paired Techtree Contest #11 - Techno Magic now!
    Dismiss Notice
  4. Dismiss Notice
  5. Hero Contest #8 is up and running! This time it's a joint contest between artists and coders. Go here for team matchmaking.
    Dismiss Notice
  6. The ninth Concept Art Contest has launched. Enter now!
    Dismiss Notice
  7. Our first StarCraft contest, The Galaxy Terraining Contest #1 - World Wonders has started. Enter to show off your Galaxy Editor skills and win a custom rank icon among other things.
    Dismiss Notice
  8. Ever wanted to get your sets ready for fast texturing while still having fun? Now it is possible with our newest Mini-Texturing Contest.
    The Skeleton Units need your dire help!
    Dismiss Notice

Basic Introduction to JASS

Discussion in 'World Editor Help Zone' started by Dezs, Dec 15, 2007.

  1. aznricepuff

    aznricepuff
    Joined:
    Feb 22, 2006
    Messages:
    749
    CreateNUnitsAtLoc() itself does not leak, but if you create a location for one of its parameters, the location can leak, so make sure to remove that location.
     
  2. Dezs

    Dezs
    Joined:
    Dec 15, 2007
    Messages:
    15
    Ok, so if I use the GUI functions to say get location of triggering unit - based on what the tuts gave, it automatically returns a point stored into a local, so because the creation of a local in the non-native function, it leaks?

    I have the CreateNUnitsAtLoc here,

    Code (vJASS):
    function CreateNUnitsAtLoc takes integer count, integer unitId, player whichPlayer, location loc, real face returns group
        call GroupClear(bj_lastCreatedGroup)
        loop
            set count = count - 1
            exitwhen count < 0
            call CreateUnitAtLocSaveLast(whichPlayer, unitId, loc, face)
            call GroupAddUnit(bj_lastCreatedGroup, bj_lastCreatedUnit)
        endloop
        return bj_lastCreatedGroup
    endfunction


    if based on this the bj_lastCreatedGroup is a global right? So I do understand it shoudln't leak, then I viewed CreateUnitAtLocSaveLast

    Code (vJASS):
    function CreateUnitAtLocSaveLast takes player id, integer unitid, location loc, real face returns unit
        if (unitid == 'ugol') then
            set bj_lastCreatedUnit = CreateBlightedGoldmine(id, GetLocationX(loc), GetLocationY(loc), face)
        else
            set bj_lastCreatedUnit = CreateUnitAtLoc(id, unitid, loc, face)
        endif

        return bj_lastCreatedUnit
    endfunction


    If based on this, I could technically achieve the same effect for createnunitsatloc by looping the native CreateUnitAtLoc only right? Now I understand what they were saying about Blizzards GUI having a lot of crappy stuff -.- Although, I there aren't leaks here either. CreateUnitAtLoc is already a native after that.

    But something Im still missing is that the tutorial here says that the CreateNUnitsAtLoc is leaky if I do it like this:
    • Actions
      • Unit - Create 1 Footman for Player 1 (Red) at (Center of (Playable map area)) facing Default building facing degrees

    Code (vJASS):
    call CreateNUnitsAtLoc( 1, 'hfoo', Player(0), GetRectCenter(GetPlayableMapRect()), bj_UNIT_FACING )


     

    So where exactly is the leak? It says I can solve the leak by setting the point variable first instead of calling the function getrectcenter(getplayablemaprect()) in the creation . .
     
  3. aznricepuff

    aznricepuff
    Joined:
    Feb 22, 2006
    Messages:
    749
    Getting location of triggering unit in GUI registers as:

    Code (vJASS):

    call GetUnitLoc( GetTriggerUnit() )
     



    GetUnitLoc() returns a location, so it must have created a location TO return. Because of that, you now have a location object taking up memory in your game. The only way to free up that memory is to store the location into a variable and remove it later.


    You can also get the same effect for CreateNUnitsAtLoc() by looping CreateUnit(). I personally like CreateUnit() cuz it uses coordinates and takes reals as parameters and not locations, so you don't have to deal with locations at all.

    As for that leaking issue, the leak is in the location returned by Center of (Playable Map Area). It's not even in the rect, because Playable Map Area registers as a bj global: bj_mapInitialPlayableArea. The Center Of... GUI function, though, is this in JASS:

    Code (vJASS):


    function GetRectCenter takes rect whichRect returns location
        return Location(GetRectCenterX(whichRect), GetRectCenterY(whichRect))
    endfunction

     



    So you can see if you don't store that location in a variable and remove it, it's going to cause memory leaks. It's also not very efficient since it has three function calls within it, so calling GetRectCenter() is actually calling FOUR functions. If you use reals instead of locations, you can do the same thing while cutting the number of function calls in half from 4 to 2 - you just have to call GetRectCenterX() and GetRectCenterY().
     
  4. Dezs

    Dezs
    Joined:
    Dec 15, 2007
    Messages:
    15
    Hmm, I thought if we use functions in that manner, the returned value would automatically be used in a parameter for the next one, right? I mean like if we do this in c++, where the returned value is automatically inserted as an argument, we don't have to worry about leaks from pointers since the function would automatically close all memory space used by the parameters once it terminates. Is it because JASS works differently?

    Lol, maybe I should'nt have studied c++ as my first language, every other one you try to learn afterwards is hell -.- WEll . . 1 step at a time. Just in the meantime, I've worked on a effective tower for the Town Hall, perhaps you could comment on it:

    • Town Hall Bow Upgrade
      • Events
        • Unit - A unit Finishes training a unit
      • Conditions
        • (Unit-type of (Trained unit)) Equal to Upgrade Bowmen Dummy Trainer
      • Actions
        • Unit - Remove (Last created unit) from the game
        • Player Group - Add (Owner of (Triggering unit)) to tempPlayer
        • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
          • If - Conditions
            • (Level of Bowmen for (Triggering unit)) Greater than 3
          • Then - Actions
            • Set tempInt = (Point-value of Upgrade Bowmen Dummy Trainer)
            • Player - Add tempInt to (Owner of (Triggering unit)) Current gold
            • Game - Display to tempPlayer the text: |cffffcc00Bowmen Up...
          • Else - Actions
            • Game - Display to tempPlayer the text: |cffffcc00Completed...
            • Unit - Increase level of Bowmen for (Triggering unit)
        • Player Group - Remove all players from tempPlayer


    The player group thing was so annoying cos I had to create a group to fit the GUI function -.- Now I'm sure I have to switch sooner or later . .

    • Town Hall Bow Attack
      • Events
        • Unit - A unit Is attacked
      • Conditions
        • (Level of Bowmen for (Attacking unit)) Greater than 0
      • Actions
        • Set tempPoint2 = (Position of (Attacking unit))
        • For each (Integer A) from 1 to 4, do (Actions)
          • Loop - Actions
            • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
              • If - Conditions
                • (Level of Bowmen for (Attacking unit)) Greater than or equal to (Integer A)
              • Then - Actions
                • Set tempPoint1 = (tempPoint2 offset by ((Random real number between 50.00 and 125.00), (Random real number between 50.00 and 125.00)))
                • Unit - Create 1 Upgrade Bowmen Archer Long Range for (Owner of (Attacking unit)) at tempPoint1 facing 0.00 degrees
                • Unit - Add a 1.00 second Generic expiration timer to (Last created unit)
                • Set tempPoint1 = (tempPoint2 offset by ((Random real number between 50.00 and 125.00), (Random real number between 50.00 and 125.00)))
                • Unit - Create 1 Upgrade Bowmen Archer 2 Short Range for (Owner of (Attacking unit)) at tempPoint1 facing 0.00 degrees
                • Unit - Add a 1.00 second Generic expiration timer to (Last created unit)
                • Wait (Random real number between 0.27 and 0.40) seconds
              • Else - Actions
                • Do nothing
        • Custom script: call RemoveLocation(udg_tempPoint1)
        • Custom script: call RemoveLocation(udg_tempPoint2)


    So far the Town Hall is doing as I liked. Just that I'm not sure if the script is clear, based on what Leak Check is saying there are no leaks (I just discovered Leak Check can't look deeper than 2 levels).
     
    Last edited: Dec 19, 2007
  5. aznricepuff

    aznricepuff
    Joined:
    Feb 22, 2006
    Messages:
    749

    C++ has garbage collection, JASS doesn't. Like I said before, JASS is a dumbed down version of C++.

    As for your triggers, they look just fine. However, for the first one, consider using Custom Script and calling DisplayTextToPlayer(), that way you don't have to deal with player groups.
     
  6. Dezs

    Dezs
    Joined:
    Dec 15, 2007
    Messages:
    15
    I see, so if based on this theory, would'nt other functions like GetTriggerUnit, or GetAttacker() be leaking unit spaces as well?

    Also, I noticed that the GUI creates some sort of string variable storing the text for DisplayTextToForce, is this string leaky since I can't find it in the variable list?
     
  7. aznricepuff

    aznricepuff
    Joined:
    Feb 22, 2006
    Messages:
    749
    Ok, perhaps I should have made this clearer earlier but there are two types of leaks in JASS. The first kind, is when a handle variable (i.e. a pointer) is not nullified. In this case the variable continues to store information and uses up memory.

    The second kind of leak is when handles are not properly destroyed/removed. Handles are objects, which means that if you create a handle (unit, location, trigger, timer, etc.), the object will use up memory. The object will continue to use up memory until it is destroyed/removed.

    Functions like GetTriggerUnit() don't create a new unit, they just return an already existing one (the unit that caused the trigger to fire). So, the second type of leak doesn't happen. Also, if you don't save the returned unit to a variable, the first type of leak won't happen either since there is no variable to leak.


    Those strings are actually not saved in your map's war3map.j file (where all of your code is saved). They are saved under the file war3map.wts, along with a bunch of other strings (like unit and ability tooltips). I'm pretty sure those strings do not leak.
     
  8. Dezs

    Dezs
    Joined:
    Dec 15, 2007
    Messages:
    15
    Oh, now I get what you mean, by callign getlocation, its actually creating an object to format the return process, so the reason it leaks is because we lose the address to the actual location of the point (like removal of a pointer before calling the delete command for dynamic arrays) instead of freeing up the space used by it first?

    So lets say I'm using unit expiration timers (the generic expiration timer), these don't leak since they're part of the unit right?

    The kind of timers that leak would be those used for triggers? So lets say I'm having a knockback trigger running a 0.05 sec timer, at every instance the trigger runs, I must destroy the timer in the actions so that it doesn't leak right?

    Just another thing i might want to ask is say for MUI abilities, could I use an array (like using the stack example from tuts) of variables used for the ability, and having a control trigger that in turn checks which index is being used, and based on this, the trigger sets another switch global that would tell the ability trigger to use a different element in the array the next time it is called. The control trigger would also perform the updating of the indexes (resetting to null) or perhaps at the end of the ability triggers.
     
  9. aznricepuff

    aznricepuff
    Joined:
    Feb 22, 2006
    Messages:
    749

    Yes, those call UnitApplyTimedLife() and they are not timer objects.


    Destroying a timer object every time it calls the callback function would be bad, because then the timer would cease to exist. When you create a timer, only one object (one timer) is created, not one object for every instance the timer expires. So, if you're going with a knockback timer, you only destroy the timer once after a set amount of time (when you don't want the knockbacked unit to move backwards anymore), so something like this:

    Code (vJASS):

    local timer t = CreateTimer() //Here the object is created and saved into a local variable so we can destroy it later
    call TimerStart( t, 0.05, true, function Knockback ) //The timer is "turned on" so to speak so that it will call Knockback every 0.05 seconds; no additional objects or anything created here so no leaks
    call TriggerSleepAction( 0.5 ) //Say you want the knockback to last 0.5 seconds
    call DestroyTimer( t ) //here you destroy the timer, freeing memory as well as stopping the timer from calling Knockback every 0.05 seconds (note that if you want only to STOP the timer and not destroy it, you need to call PauseTimer()
    set t = null //Nullify handle variable to free up memory (the variable still uses up memory even if the timer object itself is destroyed)
     




    There's no simple function to return indexes for an object within an array. You would have to use loops and stuff like:

    Code (vJASS):

    local timer t = GetExpiredTimer()
    local integer i = 0
    loop
        exitwhen ( t == udg_Timer[i] or udg_Timer[i] == null )
        set i = i + 1
    endloop
    //rest of your script using i as the array index
     



    However, depending on what you need done there are ways to get around this. For example, anything with timers (like knockback) can potentially be used with globals instead of attached handles (only possible thru vJass and structs, otherwise you get efficiency problems).