[Log in / Register]
| News | Chat | Pastebin | Donations | Tutorials | Rules | Forums |
| Maps | Skins | Icons | Models | Spells | Tools | Jass | Packs | Hosted Projects | Starcraft II Modding | Starcraft II Resources | Galaxy Wiki |
(Keeps Hive Alive)
Go Back   The Hive Workshop > Warcraft III Modding > World Editor Help Zone


World Editor Help Zone Ask general questions about World Editor features and use in this forum. If you need help fixing a trigger, please post it in Triggers & Scripts. Please review the forum rules before posting.

Closed Thread
 
Thread Tools
Old 12-18-2007, 05:45 AM   #16 (permalink)
Registered User aznricepuff
OOP freak.
 
Join Date: Feb 2006
Posts: 749
aznricepuff is a jewel in the rough (186)aznricepuff is a jewel in the rough (186)
Former Staff Member: This user used to be on the Hive Workshop staff. 
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.

Quote:
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/p...ditattachments (wc3campaigns.net, where I would normally point you, is down at the moment)

Quote:
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).
Attached Files
File Type: rar JassCraft.rar (882.2 KB, 3 views)
aznricepuff is offline  
Old 12-18-2007, 02:26 PM   #17 (permalink)
Registered User Dezs
User
 
Join Date: Dec 2007
Posts: 15
Dezs is an unknown quantity at this point (0)
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.
Dezs is offline  
Old 12-18-2007, 02:37 PM   #18 (permalink)
Registered User Dezs
User
 
Join Date: Dec 2007
Posts: 15
Dezs is an unknown quantity at this point (0)
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 -.-
Dezs is offline  
Old 12-18-2007, 09:52 PM   #19 (permalink)
Registered User aznricepuff
OOP freak.
 
Join Date: Feb 2006
Posts: 749
aznricepuff is a jewel in the rough (186)aznricepuff is a jewel in the rough (186)
Former Staff Member: This user used to be on the Hive Workshop staff. 
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.
aznricepuff is offline  
Old 12-18-2007, 11:58 PM   #20 (permalink)
Registered User Dezs
User
 
Join Date: Dec 2007
Posts: 15
Dezs is an unknown quantity at this point (0)
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)
Dezs is offline  
Old 12-19-2007, 12:45 AM   #21 (permalink)
Registered User aznricepuff
OOP freak.
 
Join Date: Feb 2006
Posts: 749
aznricepuff is a jewel in the rough (186)aznricepuff is a jewel in the rough (186)
Former Staff Member: This user used to be on the Hive Workshop staff. 
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.
aznricepuff is offline  
Old 12-19-2007, 02:44 AM   #22 (permalink)
Registered User Dezs
User
 
Join Date: Dec 2007
Posts: 15
Dezs is an unknown quantity at this point (0)
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 . .
Dezs is offline  
Old 12-19-2007, 05:26 AM   #23 (permalink)
Registered User aznricepuff
OOP freak.
 
Join Date: Feb 2006
Posts: 749
aznricepuff is a jewel in the rough (186)aznricepuff is a jewel in the rough (186)
Former Staff Member: This user used to be on the Hive Workshop staff. 
Quote:
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.

Quote:
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().
aznricepuff is offline  
Old 12-19-2007, 07:40 AM   #24 (permalink)
Registered User Dezs
User
 
Join Date: Dec 2007
Posts: 15
Dezs is an unknown quantity at this point (0)
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 by Dezs; 12-19-2007 at 08:18 AM.
Dezs is offline  
Old 12-19-2007, 08:39 AM   #25 (permalink)
Registered User aznricepuff
OOP freak.
 
Join Date: Feb 2006
Posts: 749
aznricepuff is a jewel in the rough (186)aznricepuff is a jewel in the rough (186)
Former Staff Member: This user used to be on the Hive Workshop staff. 
Quote:
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.
aznricepuff is offline  
Old 12-20-2007, 12:08 AM   #26 (permalink)
Registered User Dezs
User
 
Join Date: Dec 2007
Posts: 15
Dezs is an unknown quantity at this point (0)
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?
Dezs is offline  
Old 12-20-2007, 01:53 AM   #27 (permalink)
Registered User aznricepuff
OOP freak.
 
Join Date: Feb 2006
Posts: 749
aznricepuff is a jewel in the rough (186)aznricepuff is a jewel in the rough (186)
Former Staff Member: This user used to be on the Hive Workshop staff. 
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.

Quote:
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.
aznricepuff is offline  
Old 12-20-2007, 03:21 PM   #28 (permalink)
Registered User Dezs
User
 
Join Date: Dec 2007
Posts: 15
Dezs is an unknown quantity at this point (0)
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.
Dezs is offline  
Old 12-20-2007, 09:25 PM   #29 (permalink)
Registered User aznricepuff
OOP freak.
 
Join Date: Feb 2006
Posts: 749
aznricepuff is a jewel in the rough (186)aznricepuff is a jewel in the rough (186)
Former Staff Member: This user used to be on the Hive Workshop staff. 
Quote:
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.

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


Quote:
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).
aznricepuff is offline  
Closed Thread

Bookmarks

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are Off
Pingbacks are Off
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
JASS: A Concise Introduction Ghan_04 JASS/AI Scripts Tutorials 19 06-20-2009 11:45 AM
[JASS] An introduction to vJASS, structs and good JASS technique Blue_Jeans Triggers & Scripts 16 07-11-2008 10:31 PM
[JASS] Basic Jass Chat System Kixer Triggers & Scripts 14 05-06-2007 10:39 PM
Basic JASS Tips Daelin JASS/AI Scripts Tutorials 1 04-09-2006 11:01 PM

All times are GMT. The time now is 11:50 PM.





Powered by vBulletin
Copyright 2000 - 2008, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.5.1 PL2
Copyright © Ralle