• 🏆 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] Erm... I'm Kind Of A New JASS Triggerer, I Hope You'll Help Me Here...

Status
Not open for further replies.
Level 22
Joined
Dec 31, 2006
Messages
2,216
When you create locations, units, destructables, items etc, they take up memory, and if you don't remove these when you're done with them then you will get a memory leak, and eventually all your memory will be taken and wc3 will crash or freeze.

That is why it's important to null local variables. I hope that was easy enough to understand. There are a few more complex reasons as well.

Edit: Example of leak:

JASS:
function Leak takes nothing returns nothing
    local location loc = Location(0,0)
    call CreateUnitAtLoc(Player(0), 'hfoo', loc, 0)
endfunction

And this is how you remove it:
JASS:
function Leak takes nothing returns nothing
    local location loc = Location(0,0)
    call CreateUnitAtLoc(Player(0), 'hfoo', loc, 0)
    call RemoveLocation(loc)
    set loc = null
endfunction

Not only did I remove the location, but I nulled the variable pointing to it, which means that function is now leakless. If I had not nulled it, but just removed it, it would've still leaked, and the same if I had only nulled it and not removed it. The latter leaks the most, btw.
 
Level 12
Joined
Apr 4, 2010
Messages
862
When you create locations, units, destructables, items etc, they take up memory, and if you don't remove these when you're done with them then you will get a memory leak, and eventually all your memory will be taken and wc3 will crash or freeze.

That is why it's important to null local variables. I hope that was easy enough to understand. There are a few more complex reasons as well.

Edit: Example of leak:

JASS:
function Leak takes nothing returns nothing
    local location loc = Location(0,0)
    call CreateUnitAtLoc(Player(0), 'hfoo', loc, 0)
endfunction

And this is how you remove it:
JASS:
function Leak takes nothing returns nothing
    local location loc = Location(0,0)
    call CreateUnitAtLoc(Player(0), 'hfoo', loc, 0)
    call RemoveLocation(loc)
    set loc = null
endfunction

Not only did I remove the location, but I nulled the variable pointing to it, which means that function is now leakless. If I had not nulled it, but just removed it, it would've still leaked, and the same if I had only nulled it and not removed it. The latter leaks the most, btw.

Why ur jass functions are different from mine??
 
Level 22
Joined
Dec 31, 2006
Messages
2,216
You only need to null local variables, but that doesn't mean that you can only get leaks in local variables, but the local variables in a function are created again and again each time a function is run.

If you have global variables which are rarely used then you should null those too.
 
Level 22
Joined
Dec 31, 2006
Messages
2,216
Here are some of the functions.

JASS:
call DestroyGroup(g)                                  //Destroys a unit group
call DestroyTimer(t)                                  //Destroys a timer
call DestroyLightning(l)                              //Destroys a lightning effect
call DestroyForce(f)                                  //Destroys a player group
call RemoveDestructable(d)                            //Removes a destructible
call RemoveLocation(loc)                              //Removes a location/point
call RemoveUnit(u)                                    //Removes a unit
call RemoveItem(i)                                    //Removes an item
call RemovePlayer(p)                                  //Removes a player
call RemoveWeatherEffect(we)                          //Removes a weather effect

These remove "handles". Units, players, items, etc, are handles and it's important that they are removed when no longer used as they take up a lot of ram and they all got unique handle ids (GetHandleId(h)), and if they aren't removed (and nulled) then these ids will not be recycled. Removing triggers shouldn't be done though (and you don't create tons of triggers anyway, do you?), as it may screw with these ids.
 
Level 20
Joined
Apr 22, 2007
Messages
1,960
Think of memory leaks this way.

Say I have an apple, an orange, and a banana. I hide them in a house, and I tell you that by the end of the day, you need to eat each one. I also give you a map to find the apple and the orange, but not the banana.

What happens is that you'll find the apple and the orange, and you'll eat them, but you'll never find the banana, and it'll just linger there until the house is demolished. This is called a memory leak.

If I hide so many bananas that there are thousands upon thousands of bananas in the home, then you'd imagine there's very little room left for me to hide anything else. This is the problem with memory leaks. When there isn't room to hide any more fruits, you are in trouble.
 
Level 19
Joined
Oct 15, 2008
Messages
3,231
So can you 'Destroy' other functions too after it's used? Like, to save memory and so that you would be able to create an infinite amount of functions without breaking the limit?
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
You destroy handles ; P, lol.

Another way to think of it is like this-

When you have something like unit u = CreateUnit(...), a handle is created. What's stored in the variable is a pointer to that handle. That pointer is used to access the rest of the fields associated with that handle, like the unit's health, mana, and whatever else.

Now imagine never removing units and never having them decay. Just think of how laggy the map gets when there are 154385893454309 units on it ; P. Most of the other handles work the same way.

So, you use RemoveUnit(u) to remove the unit, or you watch it die (if it dies) and decay (decay will remove it). But wait, what about the pointer! A pointer is just an integer, an integers will auto get cleaned up, but the problem here is that handle ids get recycled.

Warcraft 3 uses a variety of safety measures to ensure that pointers can't be messed with. If you do something like this

JASS:
unit u = CreateUnit(...)
item i
call RemoveUnit(u)
set i = CreateItem(...)

Uh oh!! the handle id got recycled, meaning that u now points to an item handle (u was never nulled, so u and i have the same pointer)! Warcraft 3 prevents this from happening by requiring that all locals be null before the handle ids stored in them get recycled. Null means that there is no pointer in the handle (null is like handle id of 0). Globals aren't an issue as they are auto nulled when you try to mess with them.

Now, handle ids are eventually recycled after a long period of time (when wc3 is about to increase its handle table, it checks for locals that were not nulled and point to invalid handles).

This is simple instantiation
JASS:
struct Hello extends array
    private static integer instanceCount = 0 //how many Hello's that are created
    private static integer recycleCount = 0 //how many Hello ids that were recycled
    private static integer array recycle //an array storing recycled Hello's

    public static method create takes nothing returns Hello
        local Hello this
        if (recycleCount > 0) then //if there are Hello's waiting to be reused
            set recycleCount = recycleCount - 1 //dec counter
            set this = recycle[recycleCount] //use it
        else
            set instanceCount = instanceCount + 1 //0 is null, so first inc by 1
            set this = instanceCount
        endif
        return this
    endmethod

    public method destroy takes nothing returns nothing
        set recycle[recycleCount] = this
        set recycleCount = recycleCount + 1
    endmethod
endstruct

Now, remember arrays can only go from 0 to 8191. Imagine having 8192 Hello's created... they'd stop working because there is not enough memory left.

This is how structs in vjass actually work (though they have a bit more overhead to them). A struct that is never destroyed when it's not being used anymore is akin to a handle memory leak, and when enough of the pile up, the struct stops working (remember that all handles work off of the same handle table, meaning, in simple terms, wc3 itself crashes).
 
Level 19
Joined
Oct 15, 2008
Messages
3,231
So... Does that mean you can have an infinite number of units in a game, and all you need to remember is to clean those dead ones up first?
 
What do mean? Like, is there a JASS example? I'm really sorry...

strings are just words, like what you make the function DisplayText display... they can also be used to set the paths of certain objects like model paths

JASS:
local string Text = "Hello World"
local string Path = "Units\\Blademaster.mdl" //Note: this is a hypothetical path to the blademaster model
call BJDebugMsg(Text)
//this will show a debug message saying Hello World
call AddSpecialEffect(Path, 0.00, 0.00)
//this will show a special effect using the model on the specified path
//And oh, when you use paths, always use \\ rather than \
 
Level 19
Joined
Oct 15, 2008
Messages
3,231
Now I get it, thanks so much! Uhm... I really hope you don't mind me asking but, I usually hear that Hashtables are accompanied by Strings, what are Hashtables and is it true?
 
Now I get it, thanks so much! Uhm... I really hope you don't mind me asking but, I usually hear that Hashtables are accompanied by Strings, what are Hashtables and is it true?

hashtables are like a variable array which store variable arrays... in simpler terms its like a cabinet which lets you store data in an organized way...

and we usually use strings to organize the data inside a hashtable
JASS:
local hashtable Hash = InitHashtable()
call SaveReal(Hash, GetHandleId(Miss_Foxy), StringHash("Age"), GetAge(Miss_Foxy))
//Here we save your age into a cabinet named Hash, on a folder named Miss_Foxy, into a data sheet called Age 
//The function StringHash converts the string "Age" into an integer
//Basically you could use any integer on that part, but we use a string to better organize things
//and to make it self-explanatory

//example of directly using an integer rather than a string:
//the function above is easier to understand than this one below right?
call SaveReal(Hash, GetHandleId(Miss_Foxy), 1, GetAge(Miss_Foxy))
 
Level 19
Joined
Oct 15, 2008
Messages
3,231
Hmm... What else could I ask about that would help me in learning JASS...
Haha, you're just like my other JASS Teacher, thank you so much!

PS: By the way, what are Structs?
 
Hmm... What else could I ask about that would help me in learning JASS...
Haha, you're just like my other JASS Teacher, thank you so much!

PS: By the way, what are Structs?

structs are just another type of data storage... it saves data into variable arrays (but can also save data into non-arrays)...

JASS:
//This one
globals
   unit array Hive
endglobals

//is the same as this

struct
   unit Hive
endstruct
//this is just the basic idea
//when you learn to use them, u'll realize how amazing they are
//And structs are AWESOME, they make things a lot easier... ^_^
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
Full commented look into the background workings of structs

JASS:
//a struct that extends an array is code with the syntactic sugar of a struct
//this means that no extra code is generated

//structs normally generated create, destroy, and onDestroy
struct Hello extends array
    //instantiation can be a tricky thing. When a struct is created, you have to ensure
    //that the instance returned is unique. Furthermore, when a struct is destroyed,
    //you need to reuse that struct's instance to save on memory

    //instanceCount is a counter that continues to increase as new instances are created
    private static integer instanceCount = 0 //how many Hello's that are created

    //recycleCount is a counter that continues to increase as structs are destroyed
    //this is to ensure that destroyed instances are used the next time the struct
    //is created
    private static integer recycleCount = 0 //how many Hello ids that were recycled

    //recycle is an array that stored the destroyed instances
    private static integer array recycle //an array storing recycled Hello's

    //this is the create method, a method that creates unique instances of the struct
    //thistype is a keyword that translates into the struct's name
    //in this case, thistype would be Hello
    //if the struct was named BooYa, thistype would be BooYa
    public static method create takes nothing returns thistype
        //this is a keyword that refers to the current instance
        //static methods are like regular functions, so they don't get a this, which is
        //why I was able to declare one
        //static methods are called via struct.method()
        local thistype this

        //first check for any destroyed structs
        if (recycleCount > 0) then //if there are Hello's waiting to be reused
            //decrease the counter so that you are on the right slot in the array
            set recycleCount = recycleCount - 1 //dec counter

            //set the current instance to the destroyed struct
            set this = recycle[recycleCount] //use it
        else
            //if there are no destroyed structs, make a new one by increasing
            //the instance counter
            set instanceCount = instanceCount + 1 //0 is null, so first inc by 1

            //set the current instance to the instance counter
            set this = instanceCount
        endif

        //perform creation code here :O

        //return the created struct
        return this
    endmethod

    //destroy is called when the struct is to be destroyed
    //this is not a static method
    //a non static method translates to this (using destroy as an example)
    //public static method destroy takes thistype this returns nothing
    //the instance of the struct is automatically passed in
    //they are called via structInstance.method()

    public method destroy takes nothing returns nothing
        //remember this is passed in, so it exists!
        //store this into the recycle variable
        //the first struct destroyed would be recycle[0] = this
        set recycle[recycleCount] = this
        //increase recycle counter
        set recycleCount = recycleCount + 1

        //if create was called, recycleCount would be decreased back down to 0
        //and recycle[0] would be used

        //put destruction code here
    endmethod
endstruct

Above allows this
JASS:
local Hello h = Hello.create()
call h.destroy()

There are also method operators, overloaded operators, fields, readonly fields, and static fields.

On top of this, it would be good to learn how to do object creation using Lua. I have finally finished the scripts necessary for it and included a walk through guide ; ).

Object Creation using this ensures your scripts don't collide with other scripts.

http://www.hiveworkshop.com/forums/submissions-414/system-lua_jass_globals-185917/
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
overloaded: [], []=, ==, =, >, <, etc

Some of the comparisons aren't enabled (I rarely use them, so don't know which work and which don't, but when vjass throws an error regarding them, it gives you a list of working ones).

method operators are
JASS:
integer h
public method operator hello takes nothing returns integer
    return h
endmethod
public method operator hello= takes integer i returns nothing
    set h = i
endmethod

They can also be static. They are treated like regular fields when used
set s.hello = 5
local integer i = s.hello

fields are variables in structs >.>.

readonly fields are variables with readonly...
JASS:
struct h extends array
    readonly integer i
endstruct

Then there are interfaces and function interfaces, although I don't suggest their use as they have quite a bit of overhead o-o.
 
Level 19
Joined
Oct 15, 2008
Messages
3,231
So... It can be used in Warcraft III too? I wonder if there are others besides that one, I'm suddenly interested in the topic of Triggering and Programming Warcraft III stuff :O
 
So... It can be used in Warcraft III too? I wonder if there are others besides that one, I'm suddenly interested in the topic of Triggering and Programming Warcraft III stuff :O

Yeah, it can be used in Warcraft III as well, as long as you have Jass NewGen Pack. As far as other means of triggering in warcraft III, there is only WeWarlock (which is somewhat deprecated and not used by many). That is pretty much it though.
 
Level 19
Joined
Oct 15, 2008
Messages
3,231
Hmm... How do you actually 'make' a programming language? What does a Warcraft III one actually compose of? I'm kind of curious, sorry...
 
Hmm... How do you actually 'make' a programming language? What does a Warcraft III one actually compose of? I'm kind of curious, sorry...

warcraft's programming language is JASS... every other thing (GUI, vJASS, zinc, etc) are transformed to jass when a map compiles...

on the first question, IDK...
 
Level 19
Joined
Oct 15, 2008
Messages
3,231
Okay:)
Erm, would somebody give me a step by step guide (If you really don't mind) on how to phrase functions? Because I seem a bit confused at where to put ( )s , ' 's, endloops, globals, locals and etc, please do help me...
I'm really sorry to trouble you guys, but thank you once again for helping me, you'll definitely get credits and reputation points from me once I understand how JASS works:)
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
Level 28
Joined
Mar 25, 2008
Messages
2,955
' ' is for putting in values like strings and integers (units, texts)
Within () you put all the necessary parameters for the function you're calling

endloop ends a loop, goes like:
-loop
--exitwhen i = 8
--set i=i+1
-endloop

and globals + locals go at the top of your actions-function
 
Status
Not open for further replies.
Top