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

[JASS] Leaks

Status
Not open for further replies.
Level 13
Joined
Mar 16, 2008
Messages
941
Hm worse that this is an english site, on inwarcraft.de (german) Gexxo hat made a great leaktest.

Removing leaks is very simple:
You have to store all information you want to destroy later in variables.
When you either don't need it anymore or want to give the variable a new value u have to destroy them.

Ex:
JASS:
function foo takes nothing returns nothing
    local unit u = GetTriggerUnit()
    local location l = GetUnitLoc(u)

    blub

    call RemoveLocation(l)
    set l = null
endfunction

So lets see, removing locations is simple, just use RemoveLocation(loc) and set the variable to null. For groups the command is DestroyGroup and for forces it is DestroyForce.

Then you have to know, most "unsimple" types without strings leak.
What are simple types?
Simple types are all types that are integers or reals in Jass, so unittypes, integers :)P), reals, units(units are no real integers, but you can handle them as if they were). (Hope forgot nothing)

All other stuff has to be removed and set to null, but don't do this just at the end of a trigger:

JASS:
function foo takes nothing returns nothing
    local unit u = GetTriggerUnit()
    local location l = GetUnitLoc(u)  //Now wc3 creates a point
    
    //do something
    set l = GetRandomPoint(somewhere)
    //do something
    
    call RemoveLocation(l)
    set l = null
endfunction

So what do you do?
In the end you destroyed the point thats set in l, but the original point is still in the memory of Wc3.

I hope that you don't know most of this and I'm not writing unimportant stuff ;)

Greets, Justify
 
Last edited:
Level 13
Joined
Mar 16, 2008
Messages
941
There can be many leaks, but it's also important WHERE these leaks are.
Just try it, use a spell that creates 100 effects but don't remove them. Cast some times and your pc will start lagging, BUT if you leave that place the laggs will stop, so if leaks are shared all over the map you can have lots of them. I think no one can say exactly how many, just try to avoid them :D
And in addition, I think a not removed special effect causes a 20kb leak, the biggest leak in WC3 (unless you take a UG with 10000 units in it x.x). For example Age of Myths starts lagging on my computer after a time, i think it gets 80mb extra after 1 hour of playtime, but my computer is crap, my friends have no problem with that leakvalues.

Greets, Justify
 
Level 13
Joined
Mar 16, 2008
Messages
941
I have never done this, but if nulling is all:

JASS:
function blablub
    local unit u
    local real x
    local real y

    set u = CreateUnit(GetOwningPlayer(don't know), 'xyza', x, y) //Hope that's the right order, use JassCraft to much

    do stuf with u ...

    set u = null
endfunction

I think that should be all.
Oh, and AFAIK lifetimed units doesn't leak, you don't have to remove them, just let them die with their timers and null the variable.
Greets, Justify
 
Level 29
Joined
Jul 29, 2007
Messages
5,174
Just null every variable you make (other then globals) except Integers and Reals.
JASS:
Set varName = null

There was a list HINDY made of all the things that need to be removed/destroyed but I do not remember where he posted it.

In most cases you will need this three
JASS:
call RemoveLocation( varName )
call DestroyGroup ( varName )
call DestroyEffect ( varName )

By the way, you can set variables like this local unit u = CreateUnit(...) instead of using two lines (unless you don't have the value you want yet).

Another thing is - you would usually want to use functions that use coordinates (x,y reals) instead of locations as you do not need to remove and destroy them.
For example, instead of CreateUnitAtLoc, use CreateUnit.

The best way to learn Jass is to get either JassCraft or JNGP (Jass New Gen Pack, which is way better then JassCraft) and everytime you need a function search it in the function list.
 
Level 21
Joined
Aug 21, 2005
Messages
3,699
I'm not sure if anything I'm saying here is correct, but to know if something leaks, you need to see to the variable.

There are 2 types of variables: basic variables (reals, integers, strings) and "mixed" variables, aka Handles. The last type of variable works like this:

The variable itself (such as TempPoint being a location variable) is a pointer. Pointers are 4 bytes of memory that "point" to the location inside the memory of the "contents". Those contents basically are a set of "basic" variables. For instance: the point variable itself is a 4 byte pointer. It points to a set of 3 numbers: real x, real y, real z.
Functions such as GetLocationX(loc) are internally programmed to look at the memory the locationvariable is "pointing at", and then return the corresponding "real x".
Functions such as RemoveLocation(loc) clean up the "contents" of the pointer variable, in this example removing real x, real y and real z from the memory.
If you only do this:
set locationvar = null
Then you basically remove the "pointer" variable (thus the 4 bytes reference to the actual location). This means there's still a real x, y and z somewhere in the memory you haven't removed, and you'll never be able to remove because you just nulled the referencing locationvar pointer. As you can understand, you really don't want to have hundreds of useless x, y and z reals in your memory.
Whenever you create a locationvariable (or set the variable to GetEventLocation or something), you create a pointer AND the 3 corresponding x, y, z reals.

Another example would be a "unit" variable. Unlike the locationvariable, unit variables solely are "pointers". If you assign a unit variable to a unit, no new unit will be created (unlike point variables) on the map, but the unit variable will be "pointing" to the contents of this unit. Using GetUnitState(), you look to the piece of memory the unit pointer is "pointing" at, then look up the specific unit state, for example UNIT_STATE_LIFE. Thus, if you do:
set unitvar = null
all you do is setting the pointer reference to null. This means that the unit itself is still in the memory! In this case it'd be good, because otherwise the unit would simply disappear from the map... Units are automatically cleaned when they decayed, unlike points who stay in the memory until you tell them to be removed. The function RemoveUnit does the same as RemoveLocation.
A unit is more complex than a location, obviously. It needs to store much more information, thus will be a bigger leak (although units luckily are automatically removed when they decayed) if reference to them would be lost.

If you have much memory (e.g. 2 gig ram), you won't really feel a 1 kb leak, or many small leaks. However, not everyone has a good computer. Remember that the minimum specifications for wc3 is still 128Mb ram. While I do agree that those people should at least upgrade, leaks aren't good on any computer, so just fix em!

Last example would be a Unit Group. Again, this is just hypothetically speaking because I don't know if I'm completelly correct, but:
a unit group basically is a pointer to some sort of list. This list itself contains pointers as well! Only, these pointers are unit variables. The FirstOfGroup function basically looks into the memory the unit group is refering at, then looks at the first variable in the list, and returns this. The returned variable again is no more than 4 bytes, because it's a pointer. This pointer is a unit pointer, which is pointing to one of the units in the game.

nulling a pointer variable (nulling unit, location, group, ...) sets its value to 0. 0 is the default value of a variable which means it's pointing to "nowhere". When you use a pointer pointing to "nowhere", you basically use nothing. If you want to kill a "null" unit, well, you basically kill "nothing"...
If you try to use RemoveLocation on a "null" location, the function will detect the location is pointing to "nowhere", thus it can't clean up any contents (real x, real y, real z) anymore. In JNGP, a message will pop up saying "double free location", meaning you're trying to clean up an empty variable.

If you're unsure whether a variable is leaking or not, ask yourself if it could possibly be a pointer, or if it's simply a basic value. If it's a pointer, it'll be leaking its contents if you don't remove it properly.µ

If something I said is wrong, please correct me :)
 
Level 19
Joined
Sep 4, 2007
Messages
2,826
Eww... So much text... So much information... Unbearable... I think I got it. :D
If you null an variable or unit you actually remove it.
GhostWolf, when I saw the real x, real y, real z in the CreateUnit Function In WENG I thought "Uh... what is this?"
Could you perhaps give me an example on creating an unit with this function?(The whole Jass script)
I wanted to learn jass because I thought it could help me in learning C and C++.
I am only good at VB 5, VB 6 VB 2008 Express Edition and HTML(A little).
 
Level 21
Joined
Aug 21, 2005
Messages
3,699
the CreateUnit function ALWAYS requires x and y variables, no matter whether you use vjass or normal jass. WENG is better than WE vanilla because it contains advanced options for map editing in general, includes a "GUI" for jass, bolding out syntactical words, etc. and also includes a functionlist for easily looking up things.

Learning jass will probably help you in learning c/c++ if this is your first experience in programming.
 
Level 11
Joined
Feb 18, 2004
Messages
394
Eleandor, Learn2Format

All variables in JASS are 4 bytes long. integers and reals are your standard number types. Types in JASS may extend other types. 'Apples are fruit but are not oranges' is a good way to explain the type hierarchy. Within Warcraft 3, widget extends handle, and unit, item, and destructable all extend from widget. A function which takes a widget can take a value of any of the 3 types, whereas a function which takes a unit can only take a unit type value.

The boolean type is 0 for false, anything else for true. (There are some bugs in this. I think its unit states, I forget.)
The code type is some kind of table of constants or something.
The string type holds an integer referencing a string on an internal table of strings. strings in JASS are immutable.
The handle type holds an integer referencing an internal table of handle objects. When you create a new handle, such as creating a location, you allocate memory for it and a place for it on the handle table. WC3 does not have a decent garbage collector, and so deallocation falls on the programmer. This means that if you create a new handle-type object, you will have to manually destroy it. (A few exceptions exist, such as units. units are removed automagically when they decay. Another exception is when you create a handle you will not want to destroy. (E.g: A players hero unit in many maps.))

The handle table keeps count of references to handle objects. From what I know, the refrence counter is increased when:
  • A variable is declared with a value. E.g: local unit u = CreateUnit(...)
  • A variable is assigned a value with the set statement.

The reference counter is not increased when a value is passed to a function as a parameter.

The reference counter is only ever decreased when using the set statement. It is not increased when a function returns. (That is one hell of a bug. How the fuck did they miss that one?!)

Anyway, this supposedly affects globals as well. That is inconsequential, as the value of a global variable will eventually be changed anyway. What this truly affects on a notable level is locals. You must change the value of a local which contains a reference to a handle prior to returning to decrement the reference counter. Note that if a variable will only ever contain a handle which will not be destroyed (Such as a player), decrementing the reference counter will do nothing. The most common (and only really sensible) value variables are changed to in order to reduce the reference counter is null.
 
Level 19
Joined
Sep 4, 2007
Messages
2,826
I didn't understand it because I ain't familiar with it and it is so strange because it is designed for gaming. In other languages which I know I only know how the specific functions work and how and where to place them.
Visual Basic was simple.
HTML was too simple.
Now I'm trying to learn Jass to become better at handling rawer data to get ready for C/C++ so that is one of the few reasons I chose to learn it.
Another question: What are functions? Are they actions?
 
Level 11
Joined
Oct 13, 2005
Messages
233
You said you had visual basic experience, right? Functions in visual basic should be quite similar to the ones in JASS. From my BASIC experience (which Visual Basic is derived from and should be quite similar), there were subs and functions. Subs were basically functions that didn't return a value and functions were forced to return a value. However, in JASS there are just functions. They work almost the same way and should be fairly easy to pick up assuming you used functions in Visual Basic.
 
Level 19
Joined
Sep 4, 2007
Messages
2,826
You said you had visual basic experience, right? Functions in visual basic should be quite similar to the ones in JASS. From my BASIC experience (which Visual Basic is derived from and should be quite similar), there were subs and functions. Subs were basically functions that didn't return a value and functions were forced to return a value. However, in JASS there are just functions. They work almost the same way and should be fairly easy to pick up assuming you used functions in Visual Basic.

The problem is that I don't know what you guys are talking about... I learned VB on my own and I do not understand what liberaries, functions, handles syntaxes and etc are...

Basically what you are saying is that Functions are stuff that do something and Subs don't?
From my understanding returning value means it does something.
 
Level 29
Joined
Jul 29, 2007
Messages
5,174
Well functions are functions. Blocks of code that do something.

Functions can return values (for example bj_LastCreatedUnit is a function that returns the last created unit), or return nothing.

The triggers in warcraft are made from Events, Conditions, and Actions.

You declare in the Init function (the lowest function in every code) whats your Event, whats your Conditions function and whats your Actions function.

JASS:
function Trig_Untitled_Trigger_001_Actions takes nothing returns nothing // the actions function
endfunction

//===========================================================================
function InitTrig_Untitled_Trigger_001 takes nothing returns nothing // this is the init
    set gg_trg_Untitled_Trigger_001 = CreateTrigger(  )
    call TriggerAddAction( gg_trg_Untitled_Trigger_001, function Trig_Untitled_Trigger_001_Actions ) // this is setting the actions function
endfunction

Every "action" you use, beside setting a variable to a "basic" value (a number) is actually a function blizzard made and we can't edit.

So if you use "call KillUnit(some unit)", you can notice you called a function called "KillUnit", that takes a unit value, doesn't return anything, and kills the unit.

Thats the takes/returns.
You can give a function info, and you can return info.

So, if you would like to give a function a number, and then it will return your number*2, it'll look like this:
JASS:
function blabla takes integer i returns integer
     return i*2
endfunction

Now to call it, you use "call blabla(some integer)".
If you want to set a variable to that value, you do not need to use the "call".
So for example, if you want to set a integer called Int to be a value, it would look like this:
JASS:
locla integer Int = blabla(some integer) // no need "call"

Now as you probably noticed, when you give a function a variable type, you must give it a name (so you can refer to it inside the function), when you return however, you do not need a name because its just a value you basicly cannot refer too (unless you set it to a variable in the function that called it).

You can give a function as many info you want, you can return only one type of value.

You cannot do something like "return i and a".

Once you use the "return" command, your function will exit itself (you may know it as "Skip Remaining Actions" from GUI).

Now here's a finailizing example on how to use the function we just made:
JASS:
function blabla takes integer i returns integer
     return i*2
endfunction

function Trig_Untitled_Trigger_001_Actions takes nothing returns nothing
    set Int = blabla(4) // this will return 8
endfunction


//===========================================================================
function InitTrig_Untitled_Trigger_001 takes nothing returns nothing
    set gg_trg_Untitled_Trigger_001 = CreateTrigger(  )
    call TriggerRegisterTimerEventSingle( gg_trg_Untitled_Trigger_001, 5 ) // this is a event of "5 seconds passed from the start of the game"
    call TriggerAddAction( gg_trg_Untitled_Trigger_001, function Trig_Untitled_Trigger_001_Actions )
endfunction

As you can see, the Init's name must be called InitTrig_TRIGGERNAME.
You must assign the Event(s)/Condition(s)/Action(s) according to the trigger name aswell with this syntax: gg_trg_TRIGGERNAME.

Oh and since you asked, Syntax means "how to write it". So if you have for example a Syntax error, it means you didn't write something correctly.

Also, functions that call other functions MUST BE BELOW THEM.
If a function calles a function below itself it will be a syntax error (or some other error).
 
Level 12
Joined
Aug 20, 2007
Messages
866
Actually ...

I learned both BASIC and Visual Basic (for the most part) on my own

Believe it or not, BASIC is almost totally different from VB

BASIC is written in one gigantic loop (as all programs technically are), but VB skips all of that with it's event-driven coding

VB differentiates even further with it's object-orientation, no setting sprites and what not


Actually, VB is similar to GUI, while JASS is similar to BASIC

Probably by definition, BASIC is low-level symbolic code, comparetively speaking, JASS would also be the more efficient, lower code


Anyway, if you wanna learn JASS, learn BASIC, the Gosub functions will make JASS 10000000000000000000x more understandable (as with every other language, because symbolic/assembly code is as close to coding directly to the computer as you can get)
 
Level 12
Joined
Aug 20, 2007
Messages
866
Nah

Just the stuff you were talking about what you learned was almost exactly what a friend of mine in my programming class learned, thought perhaps you were him (he was gonna learn JASS too, and I referred him to this site, cept I think he's a bit busy for wc nowadays)
 
Level 12
Joined
Aug 20, 2007
Messages
866
Yeah I know

For me, it's like magic doesn't exist, but robotics does, which is the next best thing (robotics including computers :D)
 
Level 19
Joined
Sep 4, 2007
Messages
2,826
One question: Does this leak? I felt it was kinda unnessisary to create a new thread.
  • Black Death
    • Events
    • Conditions
    • Actions
      • For each (Integer A) from 1 to 10, do (Actions)
        • Loop - Actions
          • Set Disease = (Random unit from (Units in (Playable map area) matching ((((Matching unit) is A structure) Not equal to True) and (((Matching unit) is alive) Equal to True))))
          • Unit - Add Black Death to Disease
 
Level 19
Joined
Aug 24, 2007
Messages
2,888
I ment there are too many how to remove leaks trigger which explains nothing about what is leak to make people understand what its based
And this is sad
 
Level 12
Joined
Aug 20, 2007
Messages
866
It leaks 10 group handles

1 leak per for loop from the for loop (10 loops)
Each group is an object handle (don't worry so much what they are, rather they take up memory)

The handles are like big pieces of information, and need to be removed during gameplay because they cause the computers to hold memory it isn't using.

You must use the DestroyGroup() function in Jass, custom script --> "call DestroyGroup(udg_"PlaceYourGroupVariableHere" )<--- the udg_ signals it's a GUI variable

The proper leak fix for this would be

  • Black Death
  • Events
  • Conditions
  • Actions
  • For each (Integer A) from 1 to 10, do (Actions)
  • Loop - Actions
  • Set Disease = (Random unit from (Units in (Playable map area) matching ((((Matching unit) is A structure) Not equal to True) and (((Matching unit) is alive) Equal to True))))
  • Unit - Add Black Death to Disease
  • Custom Script: call DestroyGroup(udg_Disease)
  • Custom Script: set udg_Disease = null
  • I don't remember how to do GUI tags, but the "custom script" stuff must go in the loop!!!

You might want to keep in mind when you start using SFX (special effects, S = special
FX = Ffects) that a special effect leak is something like 1000x times the size of a location leak


Also, keep in mind variables simply "point" to a handle kind of like giving the handle a name that the computer can hear and say "Oh, him? sure I could remove him"

Handles are kinda like units (technically speaking I'd say units are a type of handle), they don't just dissappear when you change their name (nullifying the variable just removes it's name)
 
Level 19
Joined
Sep 4, 2007
Messages
2,826
How does
  • Set Disease = (Random unit from (Units in (Playable map area) matching ((((Matching unit) is A structure) Not equal to True) and (((Matching unit) is alive) Equal to True))))
create a group?
Disease is only 1 unit. -.-
 
Level 12
Joined
Aug 20, 2007
Messages
866
Ah

Groups are interesting

Groups are actually just information for the computer, not even units
Think of a group like a hat, and the unit's are little slips of paper you throw into it

First, you must get a hat (creating a group)
Next you must enumerate that hat (find units and put them into it)
Finally, you can use that hat to do numerous things, but generally keep track of all the units in one group

Basically, anytime in GUI when you set a group variable, it recreates a brand new hat, no matter if there is anything in it, or all of the units on the map

Btw, the code that you did above takes everysingle living non-structure unit and puts them into a group

(group variables point to the "hat" that the units are in, not each individual unit)
 
Level 12
Joined
Aug 20, 2007
Messages
866
Not quite

O dear, I didn't see that "Random 1"
(I thought that the Disease variable was a group, not a unit)

Sorry bout that, yeah that would basically give disease to one randomed unit ten times (I think), just how the loops work in GUI

If you are really bothered by it, you could either actually type out the function ten times, or set a group variable to all the units matching your conditions, set another one to random 10 of the first group, then use the For All units in Group function to give them each the disease

  • Actions
    • Set TempGroup1 = (Units in (Playable map area) matching ((((Matching unit) is A structure) Not equal to True) and (((Matching unit) is alive) Equal to True)))
    • Set TempGroup2 = (Random 10 units from TempGroup1)
    • Unit Group - Pick every unit in TempGroup2 and do (Actions)
      • Loop - Actions
        • Unit - Add Black Death to (Picked unit)
    • Custom script: call DestroyGroup(udg_TempGroup1)
    • Custom script: call DestroyGroup(udg_TempGroup2)
    • Custom script: set udg_TempGroup1 = null
    • Custom script: set udg_TempGroup2 = null
 
Status
Not open for further replies.
Top