JASS: Basics of Structs

Andrewgosu

The Silent Pandaren Helper
Reaction score
716
Basics of Structs

In this tutorial, I am going to introduce the basics of using structs. Namely, how to create and destroy, attach and how to operate with one.

To proceed, you will need:

- World Editor
- JASS NewGen Pack
- Average knowledge concerning JASS

Steps I intend to teach:


- What is a struct and how to declare one
- Adding a struct its components
- Creating the struct in a function and accessing its components
- Attaching the struct to a handle using a attaching system/Retrieving an attached struct
- Destroying a struct
- "create" method
- "onDestroy" method
- A nice farewell and a conclusion

Step 1 – What is a struct and how to declare one

To put it simple, structs are parallel globals arrays with a nice indexing system. No game cache involved, whatsoever.

Because structs are globals arrays, they have an instance limit, 8191, if to be exact (Fancy trivia, god I love it). But don't be frightened, as you will normally not meet this limit.


Declaring structs is very easy: firstly, you need to type out the “struct” keyword, after that, give your struct a name and lastly, close the struct with the “endstruct” keyword.

A brief example, if I may:

JASS:
struct structname
endstruct


There, you did it.


Step 2 – Adding a struct its components

A empty struct has no usage for us:

After declaring your struct, you need to add its components - the stuff you want to store.

And it's even easier than declaring a struct.

JASS:
struct structname
    unit whichPanda
    real facing
    real x
    real y
    integer level
endstruct


Struct components can have an initial value, too:

JASS:
struct structname
    real fullAngle = 90.
    integer maxNumber = 69
endstruct


What about arrays inside a struct? No problem. I mean, one problem.

When declaring arrays inside a struct, you have to set the array index limit.

JASS:
struct structname
    integer array level[100]
endstruct


This means you can use up to 100 array indexes, with 8190 divided by 100, 81 struct instances.

To conclude, the bigger a variable's array index inside the struct is, the smaller the struct instance limit gets.

Make sure to keep this is mind when using arrays inside structs, as it may have an effect to multi-instanceability.


Step 3 – Creating the struct in a function and accessing its components

For creating a struct, vJASS syntax comes into play. But, don't be alarmed and confused!

JASS:
function functionname takes nothing returns nothing
    local structname data = stuctname.create()
endfunction

I am more than sure the “local” part is very familiar to you, but you may ask what's up with the “structname” thingamajig, by now; there is no structname type, only integer, real, unit etc.

Well, yes there is. Now.

If you give a struct a name, you have to use its name for the type when creating it in a function.

A few more examples:

JASS:
function functionname takes nothing returns nothing
    local pandamonium data = pandamonium.create()
    local thehelper info = thehelper.create()
    local apple worm = apple.create()
endfunction


The “pandamonium”, “thehelper” and “apple” are given struct's names, “data”, “info”, “worm” are just the names which reference the created local structs.

Is anything left unclear at this point?

Good.


After creating the struct, you have full access to its components. Again, pay attention to the syntax, God damn it!

JASS:
function functionname takes nothing returns nothing
    local structname data = stuctname.create()
    local unit caster = GetTriggerUnit()
    
    set data.whichPanda = caster
    set data.facing = GetUnitFacing(caster)
    set data.x = GetUnitX(caster)
    set data.y = GetUnitY(caster)
    set data.level = GetHeroLevel(caster)
endfunction


You use the struct reference name “data” (it can be anything, you name it) to access the components of the created struct of type “structname”.

A few more examples:

JASS:
function functionname takes nothing returns nothing
    local haxxor gamer = haxxor.create()
    set gamer.realX = 270.
    set gamer.RealY = 90.
endfunction

function functionname takes nothing returns nothing
    local sheep grass = sheep.create()
    set grass.killer = GetKillingUnit()
endfunction


It's up to you what you call the struct and which reference name you give it, though, an explanatory name would most certainly be the best.


Step 4
– Attaching the struct to a handle using a attaching system/Retrieving an attached struct

There are plenty of attaching systems to be found, I will be using the most common ones, including the now infamous Handle Variables.

I will attach the struct to a timer called “callback”; a pseudo variable, too lazy to type it out every time. Laffle.


Attaching/retrieving a struct using:

Vexorian's CSData

JASS:
function callbackfunc takes nothing returns nothing
    local structname data = GetCSData(callback)
endfunction

function functionname takes nothing returns nothing
    local structname data = structname.create()
    call SetCSData(callback, data)
endfunction


Cohadar's ABC

JASS:
function callbackfunc takes nothing returns nothing
    local structname data = GetTimerStructA(callback)
endfunction

function functionname takes nothing returns nothing
    local structname data = structname.create()
    call SetTimerStructA(callback, data)
endfunction


Nothing overly difficult.


Step 5 – Destroying a struct

The next sentence will be very important. The previous sentence is not important.

Just messing with you.

Structs need to be destroyed, remember that! (Locations need to be removed, groups need to be destroyed...)

Leave a struct used by a timer-callback intensive spell undestroyed and you will soon hit the struct instance limit.

Yes, that is a bad thing. I are serious.


The syntax for destroying a struct is following:

JASS:
function callbackfunc takes nothing returns nothing
    call data.destroy()
endfunction


A few more examples; lets destroy the silly structs I created earlier:

JASS:
function callbackfunc takes nothing returns nothing
    call data.destroy()
    call info.destroy()
    call worn.destroy()
endfunction



Step 6 – A nice farewell and a conclusion

These were the basics of structs, the know-how you need to create, attach, retrieve and destroy structs.

Just to be on the safe side, a final example to recap:

JASS:
// Declare the struct
struct sheepfall
    // Make a list of its components
    unit whichSheep
    integer SheepLevel
    real facing
endstruct

function callbackfunc takes nothing returns nothing
    // Retrieve the struct
    local sheepfall data = GetCSData(GetExpiredTimer())
    // Destroy the struct
    call data.destroy()
endfunction

function funcname takes nothing returns nothing
    local unit sheep = GetTriggerUnit()
    local timer t = CreateTimer()
    // Create the struct
    local sheepfall data = sheepfall.create()
    // Set its componenets a value
    set data.whichSheep = sheep
    set data.SheepLevel = GetHeroLevel(sheep)
    set data.facing = GetUnitFacing(sheep)
    // Attach the struct
    call SetCSData(t, data)
    call TimerStart(t, 10., false, function callbackfunc)
endfunction


The next two steps are a bit more advanced and, optional!


Step 7– “create” method

Every time you call “structname.create()”, you might think, what is this “create()” part after the funny dot; it looks like a function, but is it one?

Methods are basically functions associated with structs (class); very crudely taken – functions inside structs which can use the struct componenets.

An example how to declare a method inside a struct:

JASS:
struct structname
    method methodname takes nothing returns nothing
    endmethod
endstruct


To declare a method, you use the “method” keyword and to end it, the “endmethod” keyword.


Lets continue to the “create” method, which you earlier used already.

JASS:
struct structname
    static method create takes nothing returns structname
    endmethod
endstruct


You might notice the “static” and “returns structname” part and it may look weird, if you are new to vJASS.

I'll explain why it looks like so.

The “static” keyword in front of the method means the method does not take a struct reference.

I'll illustrate it for you:

JASS:
struct structname
    unit caster
endstruct        
        
function funcname takes nothing returns nothing
    local structname data = structname.create()
    set data.caster = GetTriggerUnit()
endfunction


The “data” is the reference name to the newly created struct of type “structname”. You use the reference name to access the structs component “caster”.

Now, can you use “data” to create “structname”? No.

You cannot do “local structname data = data.create()”. It would not syntax.


Next, what about the “returns structname” part? That's easy, the “created” method needs to return a struct, in this case “structname”.


Lets venture further.

Every time you create a struct, it is automatically issued an unique id (the unique index number for the parallel globals arrays).

Now, if you are planning to use your own “create” method, you have to do that by hand.

JASS:
struct structname
    static method create takes nothing returns structname
        local structname data = structname.allocate()
        return data
    endmethod
endstruct


The default “create” method looks like the one above. The “allocate()” part issues the struct an unique id.

Lets change the parameter list and allow the method to take some arguments (yes, it can do that) plus, lets add a few struct components.

JASS:
struct structname
    unit caster
    real facing
    real x
    real y
    integer level
    
    static method create takes unit whichUnit, integer level, real x, real y, real facing returns structname
        local structname data = structname.allocate()
        return data
    endmethod
endstruct


Lets use the “create” method now to initialize our struct components.

JASS:
struct structname
    unit caster
    real facing
    real x
    real y
    integer level
    
    static method create takes unit whichUnit, integer level, real x, real y, real facing returns structname
        // Create the struct inside the “create” method
        local structname data = structname.allocate()
        // Initialize its components
        set data.caster = whichUnit
        set data.level = level
        set data.x = x
        set data.y = y
        set data.facing = facing
        // Return the struct
        return data
    endmethod
endstruct

function funcname takes nothing returns nothing
    local unit caster = GetTriggerUnit()
    local structname data = structname.create(caster, GetHeroLevel(caster), GetUnitX(caster), GetUnitY(caster), GetUnitFacing(caster))
endfunction


As you can see, the struct components are issued the values you insert to the parameter list when creating it in the “funcname” function.

By the way, you are doing object oriented programming, or OOP, for short.

I hope nothing is unclear at this point.


Though, to recap:

- “create” methods must have the “static” keyword in front of them.
- Use “structname.allocate()” to issue a struct an unique id.


Step 8– “onDestroy” method

You can declare your own method which runs upon a structs destruction. It is called the “onDestroy” method.

This method is particularly useful for removing leaks after the job is done.

JASS:
struct structname    
    method onDestroy takes nothing returns nothing
    endmethod
endstruct


The “onDestroy” method is not static, nor it takes or returns anything and it's very easy to use.

But how can I access the struct components, I do not create a struct there, therefore there is no reference.

Well, obviously I don't create a struct because this is a destroy method...

JASS:
struct structname
    location where
    trigger trig
    triggeraction ta
    
    method onDestroy takes nothing returns nothing
        call RemoveLocation(.where)
        call TriggerRemoveAction(.trig, .ta)
        call DestroyTrigger(.trig)
    endmethod
endstruct


You use a little dot in front of the struct's components' names to access them in the “onDestroy” method.

As you can see from the example, all the leaks are destroyed when the struct is freed.

How cool is that?


Use "create" and "onDestroy" methods together and you got yourself a deadly combination, which makes your life easier.


Thanks for reading.

Any feedback appreciated.


Andrewgosu, your favorite Pandaren.
 

Tinki3

Special Member
Reaction score
418
If I was a novice, wanting to learn VJASS, I don't think this tutorial would help
me too much with information regarding structs.

I think there is some small things that are missing though.
The tutorial is good, anyway.
 

Arkan

Nobody rides for free
Reaction score
92
I think it might come in handy for people learning vJass, good job.
 

Andrewgosu

The Silent Pandaren Helper
Reaction score
716
I think there is some small things that are missing though.

Which small things?

I did not want to bring in methods, as this is the basics of structs.

It would make things more difficult to understand for JASSers with little vJASS experience.


Declaring, creating, attaching, retrieving and destroying structs are the basics.

What more should a spell use? :p
 
Reaction score
456
Andrewgosu! I was supposed to make a tutorial like this x).. Just said so yesterday.. well.. not exactly same, but basics of vJass spells. Good, now I don't have to explain what a struct is, I can just give a link to this tutorial.

Anyway, this looks like a good tutorial, and much more clear than the previous one made by someone.. :)
 

~GaLs~

† Ғσſ ŧħə ѕαĸε Φƒ ~Ğ䣚~ †
Reaction score
180
Made some explanation about method?
Methods

Methods are just like functions, the difference is that they are associated with the class, also [normal] methods are associated with an instance (in this case 'this')

Once again an example is needed

JASS:
struct point
        real x=0.0
        real y=0.0

        method move takes real tx, real ty returns nothing
            set this.x=tx
            set this.y=ty
        endmethod

    endstruct

    function testpoint takes nothing returns nothing
     local point p=point.create()
        call p.move(56,89)

        call BJDebugMsg(R2S(p.x))
    endfunction

this : A keyword that denotes a pointer to current instance, [normal] methods are instance methods which means that they are called from an already assigned variable/value of that type, and this will point to it. In the above example we use this inside the method to assign x and y, when calling p.move() it ends up modiffying x and y attributes for the struct pointed by p.

method syntax : You might notice that method syntax is really similar to function syntax.

this is optional : You can use a single . instead of this. when you are inside an instance method. (For example set .member = value)

Methods are different to normal functions in that they can be called from any place (except global declarations) and that you are not necessarily able to use waits, sync natives or GetTriggeringTrigger() inside them (but you may use any other event response), you might be able to use them but it depends on various factors, it is not recommended to use them at all. In next versions the compiler might even raise a syntax error when it finds them.

After method, method names...
The onDestroy method

There is no actual syntax for destructors, but there is a rule and it is that if the struct has a method called onDestroy, it is always automatically called when .destroy() is issued on an instance.

It is useful to have onDestroy when an instance of the type may hold things that have to be correctly cleaned, it saves time and even makes things safer.

JASS:
struct sta
        real a
        real b
    endstruct

    struct stb
        sta H=0
        sta K=0

        method onDestroy takes nothing returns nothing
            if (H!=0) then
                call sta.destroy(H)
            endif
            if (K!=0) then
                call sta.destroy(K)
            endif
        endmethod
    endstruct


In the above example, it is only needed to destroy the object of type stb and it would automatically destroy the attached objects of type sta if present.
The onInit method

It is usual to need some initialization to be done to an struct's static members during map initialization, you can use an static onInit method to make code execute during map initialization.

Notice struct initializations are executed before any library initializer, if you require a library initializer to be executed before your initialization, use a library initializer instead. The relative order between different struct initializers is undefined.

JASS:
struct A
        static integer array ko

        private static method onInit takes nothing returns nothing //may be public as well
         local integer i=1000
             loop
                 exitwhen (i<0)
                 set A.ko<i>=i*2
                 set i=i-1
             endloop
        endmethod
     endstruct</i>



Static Method..?
Static methods

Static methods or class methods do not use an instance, they are actually like functions but since they are declared inside the struct they can use private members.

JASS:
 struct encap
        real a=0.0
        private real b=0.0
        public real c=4.5

        private method dosomething takes nothing returns nothing
            if (this.a==5) then
                set this.a=56
            endif
        endmethod

        static method altcreate takes real a, real b, real c returns encap
         local encap r=encap.create()
            set r.a=a
            set r.b=b
            set r.c=c
            call r.dosomething() //even though it is private you can use
                                 //it since we are inside the struct declaration
         return r
        endmethod

        method randomize takes nothing returns nothing
            // All legal:
            set this.a= GetRandomReal(0,45.0)
            set this.b= GetRandomReal(0,45.0)
            set this.c= GetRandomReal(0,45.0)
        endmethod

    endstruct

    function test takes nothing returns nothing
     local encap e=encap.altcreate(5,12.4,78.0)
         call BJDebugMsg(R2S(e.a)+&quot; , &quot;+R2S(e.c))
    endfunction


You might notice that the usual create() syntax works like an static method, and destroy() can work as static or instance method

You can override the static method create by declaring your own one, once you do it, you might require another method just to allocate a unique id for the struct, this is the allocate() static method which is added by default to all structs, it is a private method. When a struct does not have an specific create method declared, jasshelper will use allocate directly when .create is called.

JASS:
struct vec
   real x
   real y
   real z

   // static method create must return a value of the struct&#039;s type
   // create may have arguments.
   static method create takes real ax, real ay, real az returns vec
     local vec r= vec.allocate() //allocate() is private and
                                 //it gets a unique id for the struct
         set r.x=ax
         set r.y=ay
         set r.z=az

     return r
   endmethod

endstruct

function test takes nothing returns nothing
 local vec v= vec.create(1.0 , 0.0 , -1.0 )

    call BJDebugMsg( R2S(v.z) )

    call v.destroy()
endfunction

Static methods that take nothing can also be used as code values

    struct something
        static method bb takes nothing returns nothing
            call BJDebugMsg(&quot;!!&quot;)
        endmethod
    endstruct

    function atest takes nothing returns nothing
     local trigger t=CreateTrigger()
         call TriggerAddAction(t, function something.bb)
         call TriggerExecute(t)
    endfunction

Global Struct type..?
Globals of struct types

You can have globals of struct types. Because of Jass' limitations you cannot initialize them directly.

JASS:
globals
     pair globalpair=0 //legal
     pair globalpair2= pair.create() //not legal
endglobals


You would have to assign them in an init function instead.
 

cr4xzZz

Also known as azwraith_ftL.
Reaction score
51
Huh, you're the man... I read tens of tuts and none of them helped. Now I understand these structs + using attachment systems like kattanas' handle vars.
<3
 

Andrewgosu

The Silent Pandaren Helper
Reaction score
716
Made some explanation about method?

I stated I did not want to bring methods in.

But, coming to think about it, I shall add "create" and "onDestroy" method.


P.S Any fool can read the vJASS documentation page, but, can they understand it...No.

That's why I made a simple tutorial.

And it has information about struct attaching what's really important.
 

Cohadar

master of fugue
Reaction score
209
I disagree with you ~Gals~.
Methods belong to the advanced part of jass.

EDIT:
Also my personal opinion is that Kattana's Handle Variables should not be used any more.
(and if I might add, most pro jassers will agree with me on that one)

Learning handle variables can actually do more damage than good to a novice coder.
 

~GaLs~

† Ғσſ ŧħə ѕαĸε Φƒ ~Ğ䣚~ †
Reaction score
180
>>I stated I did not want to bring methods in.
Maybe I missed it out.

>>P.S Any fool can read the vJASS documentation page, but, can they understand it...No.
That is not an explaination, it is just a concisious that I was reading the manual and suddenly found this thread.
I'll probably only write those 4 sentence but I wasted my time for copy and paste it here, in case someone need the minimal information on those item i stated.

Indeed, someone may not know there is a vJass documentation page in the NewGen Folder.

>>And it has information about struct attaching what's really important.
Why, why you didn't add in Handle Struct Attachment System??I assume that you don't even know it exist??

Edit -
>>I disagree with you ~Gals~. Methods belong to the advanced part of jass.
The decision is on Andrew, as I didn't said "You Must Add The MeTHoD PaRt to the tutorial !!!"

>>Also my personal opinion is that Kattana's Handle Variables should not be used any more.
True, Gamecache sucks.
Instead of CSData, why not add-in CSCache too? Probably it also involve to gamecache. =.=
 

Cohadar

master of fugue
Reaction score
209
Why, why you didn't add in Handle Struct Attachment System??I assume that you don't even know it exist??
Because it does the same thing as CSData only in a more complicated way?
I strongly discourage people against using HSAS.
It is just another 0x10000 system that adds to global system confusion.
I would always prefer people using CSData over it.

I here apologize to my friend PandaMine for bashing his sys, but it is true, HSAS sux.
(I recommend people to try some of his other systems like AMHS or AFS)
 

Andrewgosu

The Silent Pandaren Helper
Reaction score
716
Also my personal opinion is that Kattana's Handle Variables should not be used any more.
(and if I might add, most pro jassers will agree with me on that one)

Learning handle variables can actually do more damage than good to a novice coder.

Yes, maybe. Maybe not. Depends on the coder.


Yes, they are outdated.

However, I cannot ignore the fact quite many still use them.

Personally I think it should contain an explanation of what a struct -is-...

"To put it simple, structs are parallel globals arrays with a nice indexing system."

Why, why you didn't add in Handle Struct Attachment System??I assume that you don't even know it exist??

"There are plenty of attaching systems to be found, I will be using the most common ones"

Don't see many people using HSAS.

Plus, all the attaching systems attaching/retrieving function calls are really similar, no matter they operate a little differently.

One should thank god I even posted 3 different examples instead of 1 generic, but not so explanatory, one.


Thank you all for feedback.
 

~GaLs~

† Ғσſ ŧħə ѕαĸε Φƒ ~Ğ䣚~ †
Reaction score
180
>>@Cohadar
Well, I knew that... HSAS is bad as it uses the 0x10000 thingy you said in the H2I. But, the most important thing that HSAS has is, any handle can get the chance to get attached. Don't argue with me, I know I am a useless thing as far as I know, I should use ABC, no others. Sorry.

>>One should thank god I even posted 3 different examples instead of 1 generic
So that I should get scolded back for asking for more... Sorry, my appology.

@Andrew
You may explain that struct may use as global. :D
 

Cohadar

master of fugue
Reaction score
209
offtopic: (really sorry)

>>@Cohadar
But, the most important thing that HSAS has is, any handle can get the chance to get attached.
That is exactly the reason it sux.
Also gamecache sux mostly for the same reason.
I already had discussions on spaghetti code and I will not repeat it here.

If anyone wants more details you can PM me or open a new thread.
 

The Undaddy

Creating with the power of rage
Reaction score
55
Question (back on topic).
If I attach a struct then I attach all its variables and methods and whatever else I don't know structs have,right?So no more attaching a caster unit,a target unit,an integer for who knows what..*time passes*...a real for ang.... Yeah.:D

And when creating a struct in a trigger,It's unique every time it's created?No ruining Multi everything instanceability?
 

N2o)

Retired.
Reaction score
51
Nice tutorial, +rep (if i can), maybe you should mention what structs are used for. Why didn't you bring this out earlier it would of helped me with my tower contest entry.
 
General chit-chat
Help Users
  • No one is chatting at the moment.
  • Varine Varine:
    I ordered like five blocks for 15 dollars. They're just little aluminum blocks with holes drilled into them
  • Varine Varine:
    They are pretty much disposable. I have shitty nozzles though, and I don't think these were designed for how hot I've run them
  • Varine Varine:
    I tried to extract it but the thing is pretty stuck. Idk what else I can use this for
  • Varine Varine:
    I'll throw it into my scrap stuff box, I'm sure can be used for something
  • Varine Varine:
    I have spare parts for like, everything BUT that block lol. Oh well, I'll print this shit next week I guess. Hopefully it fits
  • Varine Varine:
    I see that, despite your insistence to the contrary, we are becoming a recipe website
  • Varine Varine:
    Which is unique I guess.
  • The Helper The Helper:
    Actually I was just playing with having some kind of mention of the food forum and recipes on the main page to test and see if it would engage some of those people to post something. It is just weird to get so much traffic and no engagement
  • The Helper The Helper:
    So what it really is me trying to implement some kind of better site navigation not change the whole theme of the site
  • Varine Varine:
    How can you tell the difference between real traffic and indexing or AI generation bots?
  • The Helper The Helper:
    The bots will show up as users online in the forum software but they do not show up in my stats tracking. I am sure there are bots in the stats but the way alot of the bots treat the site do not show up on the stats
  • Varine Varine:
    I want to build a filtration system for my 3d printer, and that shit is so much more complicated than I thought it would be
  • Varine Varine:
    Apparently ABS emits styrene particulates which can be like .2 micrometers, which idk if the VOC detectors I have can even catch that
  • Varine Varine:
    Anyway I need to get some of those sensors and two air pressure sensors installed before an after the filters, which I need to figure out how to calculate the necessary pressure for and I have yet to find anything that tells me how to actually do that, just the cfm ratings
  • Varine Varine:
    And then I have to set up an arduino board to read those sensors, which I also don't know very much about but I have a whole bunch of crash course things for that
  • Varine Varine:
    These sensors are also a lot more than I thought they would be. Like 5 to 10 each, idk why but I assumed they would be like 2 dollars
  • Varine Varine:
    Another issue I'm learning is that a lot of the air quality sensors don't work at very high ambient temperatures. I'm planning on heating this enclosure to like 60C or so, and that's the upper limit of their functionality
  • Varine Varine:
    Although I don't know if I need to actually actively heat it or just let the plate and hotend bring the ambient temp to whatever it will, but even then I need to figure out an exfiltration for hot air. I think I kind of know what to do but it's still fucking confusing
  • The Helper The Helper:
    Maybe you could find some of that information from AC tech - like how they detect freon and such
  • Varine Varine:
    That's mostly what I've been looking at
  • Varine Varine:
    I don't think I'm dealing with quite the same pressures though, at the very least its a significantly smaller system. For the time being I'm just going to put together a quick scrubby box though and hope it works good enough to not make my house toxic
  • Varine Varine:
    I mean I don't use this enough to pose any significant danger I don't think, but I would still rather not be throwing styrene all over the air

      The Helper Discord

      Members online

      No members online now.

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top