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.
Struct components can have an initial value, too:
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.
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:
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:
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:
Cohadar's ABC
JASS:
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:
A few more examples; lets destroy the silly structs I created earlier:
JASS:
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:
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:
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.
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.