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

Basic Introduction to JASS

Status
Not open for further replies.
Level 2
Joined
Dec 15, 2007
Messages
15
Hmm, so if BJ functions leak, does it mean all of them? When I converted some of the GUI triggers, functions like expirationtimer got a BJ suffix, so those are leaky? If so, then my tower would be a hell of a leak esp since it adds up on every attack. How do I settle this (In simple coding of course)?

Another problem I encourntered after a little thought is regarding the upgrading method I'm using. What I want to create is upgrades that stack on a tower without changing the base unit (simply adding abilities), but I can't figure out a method to perform this smoothly.

I tried using the train unit, but obviously if I remove availability when the ability reaches max, all other towers lose it.

If I use the upgrade method, The icon is messed up sicne it must upgrade into a building of the same type (An upgrade button with the same icon as the tower looks wierd). If I apply a different icon (just to illustrate the upgrade) from the tower's standard, it shows when the player selects multiple towers and looks wierd.

If I use the research method (research, then reset the research to enable research again), I can't remove the research button when the ability reaches cap. Although I can create a trigger to refund and display a message, the research button stays there, which is not so nice.
 
Last edited:
Level 19
Joined
Aug 24, 2007
Messages
2,888
umm DONT USE TUTORIALS :p
find a jass example and learn

Sorry Tutorial Submissionators (english has pwn3d)
 
Level 11
Joined
Feb 22, 2006
Messages
752
First of all, read this: http://www.hiveworkshop.com/forums/showthread.php?t=16456

It's a great tutorial. I read it when I was first learning JASS and it helped me A LOT. After reading the tutorial I suggest you start making simple custom spells with JASS or open up spell demo maps and looking at the code - that's the fastest way to learn JASS once you know the basics.

Now, as for your questions:

  1. No, you can't do it with GUI (at least not very efficiently if you want multi-instanceability) I'll let Daelin explain the rest here: http://www.hiveworkshop.com/forums/showthread.php?t=22710 (even includes instructions on how to create a knockback effect with JASS)
  2. Jasscraft (http://www.hiveworkshop.com/resources_new/tools/469/) has a function list for every function in existence in JASS (as well as names for blizzard-coded global variables like bj_lastCreatedUnit and such). The functions are listed with their parameters, what they return, and if they are not natives, what code they contain.
  3. No. I don't know how else you would expect to write JASS without typing it. But don't worry, if you are going into even slightly complex code (like knockback, for example), typing out JASS is actually faster than trying to do it with GUI. And btw, JASS is more similar to C++ than to Java.
 
Level 2
Joined
Dec 15, 2007
Messages
15
Thanks a lot for the links, but some of the resources are no longer avaiable (well those cna wait for now, i'm still getting the hang of the GUI) at the moment I've tried to get my first custom 'tower' working, but there are some problems around it.

Basically I want to create a Castle that fires multiple arrows from different positions, different firing times to create an arrow shower.

So, at the moment, I created a dummy ability for the upgrade icon on the Castle, a dummy unit that can be trained (renamed as an upgrade) for extra attacks, dummy archers that can attack created on the Castle (small x,y variations).

I'm using a simple trigger that tracks the creation of the dummy upgrade unit to apply the updated icon label, and to remove availability of the unit once it reaches cap level. Up till here the upgrade works fine, but I can't destroy the dummy archers if the Castle dies - I looked up the pick units, and didn't work with units having locust, and the only way I've managed to destroy the dummy archers is with a unit group variable, but its global so if I use that i can only have 1 castle.

How do I change the trigger to be able to record every single instance of a Castle and efefctively preserve the destroy trigger? (I'm still working on GUI, obviously)

Also, is there a setting to make projectiles inaccurate? I think I havent noticed any of those in the object editor.
 
Level 11
Joined
Feb 22, 2006
Messages
752
Jeez, I haven't worked in GUI for that kind of stuff for so long I have NO idea how to do it without JASS lol...

Don't you wish WE supported 2 dimensional arrays?

If you don't mind a little bit of JASS, however, I can give you a system:

In the Custom Scripts section of your map (click on the tft map icon at the very top of your trigger tree), copy-paste these functions:

JASS:
function H2I takes handle h returns integer
    return h
    return 0
endfunction

function HandleVars takes nothing returns gamecache
    return InitGameCache( "jasshandlevars.w3v" )
endfunction


function AttachObject takes handle h, string key, handle value returns nothing
    call StoreInteger( HandleVars(), I2S(H2I(h)), key, H2I(value) )
endfunction

function GetAttachedGroup takes handle h, string key returns group
    return GetStoredInteger( HandleVars(), I2S(H2I(h)), key )
    return null
endfunction

function FlushVars takes handle h returns nothing
    call FlushStoredMission( HandleVars(), I2S(H2I(h)) )
endfunction


Then:

Make a trigger detect every time a castle is built (Event - Unit Finishes Construction)

For Actions, put:

Custom Script: local unit castle = GetConstructedStructure()
Custom Script: local group g = CreateGroup()
Custom Script: call AttachObject( castle, "dummygroup", g )
Custom Script: set castle = null
Custom Script: set g = null

Have a trigger detect every time one of your dummy archers is trained (Event-Unit Finishes Training a unit)

For Actions, put:

Custom Script: local unit dummy = GetTrainedUnit()
Custom Script: local unit castle = GetTriggerUnit()
Custom Script: call GroupAddUnit( GetAttachedGroup( castle, "dummygroup" ), dummy )
Custom Script: set dummy = null
Custom Script: set castle = null

Then, have another trigger detect when a castle dies (Event - A unit Dies, Conditions - Unit Type of <Triggering Unit> is equal to...)

For Actions:
Custom Script: local unit castle = GetTriggerUnit()
Custom Script: local group g = GetAttachedGroup( castle, "dummygroup" )
Custom Script: local unit u
Custom Script: loop
Custom Script: set u = FirstOfGroup( g )
Custom Script: exitwhen ( u == null )
Custom Script: call RemoveUnit( u )
Custom Script: call GroupRemoveUnit( g, u )
Custom Script: endloop
Custom Script: call DestroyGroup( g )
Custom Script: call FlushVars( castle )
Custom Script: set castle = null
Custom Script: set g = null

I've basically used what is known as "attached handles" to save dummy archers to the castle that built them. So, when the castle dies, you can easily retrieve the archers assigned to that castle and remove them from the game. If you want to know more about attached handles, read Daelin's advanced JASS tutorial: http://www.hiveworkshop.com/forums/s...ad.php?t=22710 (same link as in my previous post).

One caveat is that what I've given you above will leak. It won't be as bad as leaking special effects or lightning (in other words your game won't start to lag horribly within 2 minutes of building castles) but the leaks will nevertheless be present. The leak issue (and incidentally the problem with 2-dimensional arrays) can be solved using more advanced JASS but since you're a beginner I'm not going to get into that.

If you were wondering its the constant calling of the HandleVars() function that causes the leaks because InitGameCache() leaks every time you call it. But don't worry, it's a very minor issue that should not cause any problems.

Btw, I'm not sure what you mean by "inaccurate projectiles". There's an option on unit attacks to make them not homing so they don't always hit (like with mortar teams and such).
 
Level 2
Joined
Dec 15, 2007
Messages
15
Okay . . . gimme a while to comprehend that lol . . I've been spending most of the day staring into walls of text here and there, trouble is I find that the tutorials are throwing me pieces from everywhere -.-

In terms of programming concepts, I'm fine with that since I already know C++, so the concepts like leaks, how to make this do that and then do that is not much of a problem. I'm still trying to find a good resource that can apply the JASS language step by step (Well, not to the extent of what is a function -.-) - almost like when you're tkaing up the your first class for Java (Yeah, I remember it sucked, and I still hate Java).

Oh, ya and regarding the inaccurate projectile thingy, what I mean is say like when I was playing around with CnC:Generals, the INI's had inaccuracy built into the units, it had a value called inaccurracy radius or something like that. What it does is to make the attacker inherently inaccurate, not that the projectile can't track, but his hand can't aim straight. Currently, even if the tracking is removed, the tower is still precisely accurate over the rnage of thousands (aiming ahead). So, is there a simple value that can make the unit aim with less precision?

Thanks a lot for the help . . I'll take some time to look around again later -.- Now I need let go of stress a bit -.-
 
Level 11
Joined
Feb 22, 2006
Messages
752
Lol I need to get rid of stress too, but that won't be happening anytime soon....

Well if you know C++ then JASS should be no issue cuz in my opinion JASS is just a dumbed down version of C++. It's just memorizing what function does what and what JASS can and can't do (i guess mostly wut it can't do if you already know C++)

Regarding the inaccuracy, I don't know of any way to make a unit inherently inaccurate.
 
Level 2
Joined
Dec 15, 2007
Messages
15
ALrite, aftera good nites sleep, I'm ready to ge tback to work again . . anyway I've figured out another solution around it, say:

Train dummy upgrade unit -> Increase ability level -> When castle attack -> Create dummy archer -> Wait -> Remove Dummy Archer -> When castle attack -> .. .

So technically, this allows multiple castles, each being wacthed by the trigger, but my guess is that it would be a very processor intensive thing since every attack we have units spawning and being removed, so I just wanna ask how efficient is this algorithm? I've seen various maps also having like every second events, I'm not sure but these kind of events are also processor intensive right?

Another thing I'd like to clarify is with regard to variables, say I have a global variable I use to temporarily store a point, but I don't nullify it, so there is a leak. However, the next time I use that variable, I replace the value, so tehnically the leak doesn't increase in size, right? I'm not sure about dynamic variables like those in C++, or does it occur whenever we decalre our own locals only, then we have leak problems? I also read that many standard/library functions also leak, so does that mean that the GUI functions provided themselvs are leaking internally?
 
Level 11
Joined
Feb 22, 2006
Messages
752
I'm not sure how processor intensive your new system is. Really the best way to find out is just to test it in-game.

If you don't nullify globals, it's no problem because theres only one variable. It's only with locals where every time the function is called a new local is created and if you don't nullify those variables eventually you have a bunch of local variables using up memory (strings, integers, reals, and booleans don't leak, though).

As for functions, natives usually don't leak, lots of BJ functions (functions with the suffix BJ, like ForGroupBJ) do leak. Not all GUI functions call BJ functions, though most do. BJ functions are also less efficient than natives because all they do is call other natives.
 
Level 2
Joined
Dec 15, 2007
Messages
15
Oh i see, so these variables don't automatically close after the end of a function. .

About the processing thing, what I mean is comparing towards the solution you provided, that is instead of continously create - destroy vs create then wait till death - remove. I gues what I'm trying to say is whether it is worthwhile -
 
Level 11
Joined
Feb 22, 2006
Messages
752
I really don't know how efficient or inefficient creating/removing units every time castles attack is, but I would guess that my way of just using the attached handle variables is more efficient.

My advice is use my system if you can understand it well enough. If you have no clue how my system works and will spend hours just figuring out how to implement it/tweak it to fit in your map then just go with your idea.
 
Level 2
Joined
Dec 15, 2007
Messages
15
Hmm, so if BJ functions leak, does it mean all of them? When I converted some of the GUI triggers, functions like expirationtimer got a BJ suffix, so those are leaky? If so, then my tower would be a hell of a leak esp since it adds up on every attack. How do I settle this (In simple coding of course)?

Another problem I encourntered after a little thought is regarding the upgrading method I'm using. What I want to create is upgrades that stack on a tower without changing the base unit (simply adding abilities), but I can't figure out a method to perform this smoothly.

I tried using the train unit, but obviously if I remove availability when the ability reaches max, all other towers lose it.

If I use the upgrade method, The icon is messed up sicne it must upgrade into a building of the same type (An upgrade button with the same icon as the tower looks wierd). If I apply a different icon (just to illustrate the upgrade) from the tower's standard, it shows when the player selects multiple towers and looks wierd.

If I use the research method (research, then reset the research to enable research again), I can't remove the research button when the ability reaches cap. Although I can create a trigger to refund and display a message, the research button stays there, which is not so nice.
 
Level 11
Joined
Feb 22, 2006
Messages
752
Not all BJ functions leak, only some do. But all of them are less efficient than natives because all they do is call natives, and useless repetitive function calls will just slow down your game for nothing.

By the way, just because a function doesn't have a BJ suffix doesn't mean it is a native. Take, for example:

JASS:
function GroupAddUnitSimple takes unit whichUnit, group whichGroup returns nothing
    call GroupAddUnit(whichGroup, whichUnit)
endfunction


GroupAddUnitSimple() is not a native, all it does is take the parameters, flip the order, and call GroupAddUnit(), which is a native. Basically Blizzard uses two functions to do the job of one. Pretty useless...and you can find lots more like these.

functions like expirationtimer got a BJ suffix, so those are leaky?

If you are talking about TimerStartBJ(), no the function itself does not leak, but if you don't destroy the timer after you are done with it, it will take up memory.

An example of a leaky non-native would be:

JASS:
function GetUnitsOfTypeIdAll takes integer unitid returns group
    local group   result = CreateGroup()
    local group   g      = CreateGroup()
    local integer index

    set index = 0
    loop
        set bj_groupEnumTypeId = unitid
        call GroupClear(g)
        call GroupEnumUnitsOfPlayer(g, Player(index), filterGetUnitsOfTypeIdAll)
        call GroupAddGroup(g, result)

        set index = index + 1
        exitwhen index == bj_MAX_PLAYER_SLOTS
    endloop
    call DestroyGroup(g)

    return result
endfunction


If you notice, the local groups g and result are never nullified and so those variables (being handles) will continue to use up memory even after the function closes.

Regarding your tower upgrade problem, I can't think of a system much better than the ones you've already considered.
 
Level 2
Joined
Dec 15, 2007
Messages
15
Okay, so if I want to clear out the leaks, I'll have to convert them and then add my own codes to clean them up? Or do I have rewrite the entire block (that settles leaks) that the non-native is supposed to do?

Or is it possible to create function overrides for JASS? Then I could write a global function that can be called in place of the non-natives.

I've been looking into the resource pages as well, so is there anything there that is reccomended for me to install? Theres quite a lto of stuff, but I'm trying out WorldEditorUnlimited, LeakCheck, etc

Another thing I realised during my experimentation by creating dummy achers only when the castle attacks is that it interfered with another castle attacking as well (initially I used a wait trigger then proceded to remove last created unit), ending up with units not beign removed. After changing it to use expiration timers, it works fine.

So does this mean that only one instance of the trigger can execute at once and must be finished before it can execute again? Is the trigger limited to track one event and condition (Meaning that say like I upgrade 6 towers simultaneously, only one instance will trigger, not all 6)?
 
Last edited:
Level 11
Joined
Feb 22, 2006
Messages
752
I've attached JassCraft to save you some time.

If you want to get rid of leaks, it depends on what leaks you're trying to get rid of. You basically have to learn what leaks are, what kinds of variables leak, and how to get rid of leaks. There isn't a universal step-by-step guideline to get rid of leaks.

There are, however, some very common leaks in GUI:

  1. Pick Every Unit in Unit Group and Do Actions: People use the "For Group" GUI function lots of times to do actions on a group that is created on the spot - basically the group wasn't saved in a global and isn't a bj global. For example, you might have something like Pick Every Unit Within 500.00 of <some unit> and Do Actions. Well, the problem is, the GUI function will create the unit group as it is called and by default WILL NOT DESTROY IT when it's done using the group.

    The easiest way to fix this is to go to Custom Script in GUI and type in: set bj_wantDestroyGroup = true right before the For Group GUI function is called. This tells the function to destroy the group after it's done using it, preventing memory leaks. Note you have to do set bj_wantDestroyGroup = true every time before a For Group function because the function resets the value to false whenever it is called.

    IMPORTANT: Don't set bj_wantDestroyGroup equal to true if you don't want the group to be destroyed, i.e. if you are using a group saved in a global that you want to use later, or if you are using a bj global.

  2. Locations: Locations are used a lot in GUI, from Location of <unit> to Location of Issued Order. The problem is that all of those functions create and return locations that use up memory, and thus can cause memory leaks. If you don't store those locations in variables and later destroy them (and of course nullify the variables once you're done) the locations will remain in memory as long as the map is running.

    There are two ways to fix this: use Custom Script to assign the locations to local variables, then at the end of the trigger just call RemoveLocation() and then nullify your locals,

    OR

    Avoid locations altogether. Locations are nothing but a pair of (x,y) coordinates in handle form. Almost every function that returns or uses locations has a counterpart that returns or uses (x,y) coordinates. The benefit of coordinates is that they are reals, and never leak. Unfortunately, GUI avoids those functions altogether (even the "Coordinates" function just takes reals as parameters and then turns around and returns a location). So, if you want to use reals, you have to use JASS in lieu of GUI.

Then I could write a global function that can be called in place of the non-natives.


There's really no point in that, since your new function would basically end up calling more natives. Therefore, you might as well use the native functions to begin with, since it's faster that way with less function calls.

As for resources, use JASS NewGen pack, it's way btr than WEU, especially if you're getting more into JASS. WEU's custom GUI functions and stuff basically just call standard JASS functions that already exist, and so there's nothing WEU can do that you can't already do with JASS in normal WE. NewGen, however, among other things, comes with a custom syntax checker/compiler that DOESN'T crash whenever you're missing an endif or and endloop. It also allows you to use structs and makes JASS more in-line with OOP (does this by way of preprocessor, not a hack, so it's 100% compatible with wc3 and battle.net). Get it here: http://www.hiveworkshop.com/forums/profile.php?do=editattachments (wc3campaigns.net, where I would normally point you, is down at the moment)

So does this mean that only one instance of the trigger can execute at once and must be finished before it can execute again? Is the trigger limited to track one event and condition (Meaning that say like I upgrade 6 towers simultaneously, only one instance will trigger, not all 6)?


Well, you know C++ so you should know that computers can only only run one line of code at a time (wc3 does not support parallel processing). However, you should assume that multiple instances of triggers can, for simplicity's sake, be triggered at one time, because the script DOES NOT NECESSARILY HAVE TO RUN IN ORDER. If you have a Wait function in your trigger, all it does is stop the script for that instance of the trigger and cause the wc3 engine to process pending code from other triggers (even other instances of the same trigger); it's not like if you use a wait function the part of the wc3 engine that processes the script all grinds to a halt.

The problem you had with waits is that the function Get Last Created Unit in GUI actually just returns a bj global unit variable that changes every time a GUI function creates a unit (all BJ functions that create units update the bj global when called, natives do not). So, lets say you have two Castles. One attacks, triggering your trigger. The trigger creates the unit and sets bj_lastCreatedUnit to the dummy it just created. Then, the trigger hits the wait function; it stops running scripts on that trigger for the time being. While it's waiting, another castle attacks, and another instance of the SAME TRIGGER is triggered and another dummy is created (for the second castle). Now, when this happens, bj_lastCreateUnit is updated to hold the SECOND dummy archer (there's only one variable and it only holds one unit). Now, when the wait is over for the first instance of the trigger, when you call Remove Last Created Unit, the Last Created Unit function will no longer return the first dummy archer, but rather the second (because bj_lastCreatedUnit was updated during the Wait).
 

Attachments

  • JassCraft.rar
    882.2 KB · Views: 28
Level 2
Joined
Dec 15, 2007
Messages
15
Hmm, the reason I was thinking of using overrides was simply to avoid having me rewrite the code everytime I want to use a leaky function. Well its true it would prolly be slower, just for my convenience, I guess.

So if based on what u're saying about locations, everytime I want to use one, I add custom scripts to create a local, use the function and return the location into the local first, then do what I need to do, finally clear the local?

Another thing is say regarding the leaking expiration timers, what do I have to do to clear them out when they expire? Is there a value like wantDestroyTimer or something like that? Even though I'm just starting off my TD, I just want to make sure I'm doing the steps right so I don't have to run back again later.

Thanks a lot for the explanations, I really appreciate it since I havent been able to get clear answers from the tutorials. I'll take some time off to look into JassCraft.
 
Level 2
Joined
Dec 15, 2007
Messages
15
Oh yeah, I also just downloaded Leak Check. I'm just wondering how effective it is . . Is the current version capable of detecting every possible leak from GUI? Maybe I'd use this to check then only use custom scripts to deal with lekay parts for the time being. I'm looking around at the list of functions, so for now maybe 1 or 2 lines at most -.-
 
Level 11
Joined
Feb 22, 2006
Messages
752
Yes, you need to remove the location when you are done with it using the function RemoveLocation(), then make sure you nullify your local location variable.


There's no bj_wantDestroyTimer. In fact, wantDestroyGroup is the only bj local that makes GUI functions destroy handles.

If you are going to only use a timer ONCE (it's not periodic), then for the function or trigger that is called when the timer expires, just destroy the expired timer (not sure if there's a GUI function for that, if there isn't, then do:

JASS:
set local timer t = GetExpiredTimer()
//...your actions here
call DestroyTimer( t )
set t = null


Needless to say, once you destroy a timer, it will stop working, so only destroy timers when you have no more use for them.

Regarding Leak Check, I've never used it so I have no idea how it works or how good it is.

Btw, the best way to learn JASS functions is just to take some GUI triggers in your map, copy them and convert the copy into Custom Script. Then, look at the JASS (since you already know what the trigger is supposed to do cuz you originally made it in GUI, you can get a feel for what the JASS does). Then afterwards you can try identifying leaks or use Jasscraft to search for native counterparts to replace all the BJ functions and make the code more efficient.
 
Level 2
Joined
Dec 15, 2007
Messages
15
Yep, for the time being thats what I'm trying to do, though theres so many things around. I'll be trying to open a few other TD maps to see what they have inside too. .

Just another concern thta I came across a while ago:

The function CreateNUnitsAtLoc leaks right?

Or does it only leak when I use a return function like getunitposition to set the create location? If I use a location variable directly it doesn't right?

For some reason, Leak Check is telling me its not a leak -.- Even tho I'm using the leaky method (based on the leak tut)
 
Level 2
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,

JASS:
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

JASS:
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
JASS:
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 . .
 
Level 11
Joined
Feb 22, 2006
Messages
752
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?

Getting location of triggering unit in GUI registers as:

JASS:
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.

If based on this, I could technically achieve the same effect for createnunitsatloc by looping the native CreateUnitAtLoc only right?


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:

JASS:
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().
 
Level 2
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:
Level 11
Joined
Feb 22, 2006
Messages
752
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?


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.
 
Level 2
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?
 
Level 11
Joined
Feb 22, 2006
Messages
752
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.

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?


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.
 
Level 2
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.
 
Level 11
Joined
Feb 22, 2006
Messages
752
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?


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

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?


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:

JASS:
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)


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


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

JASS:
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).
 
Status
Not open for further replies.
Top