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

[General] Structs

Status
Not open for further replies.
Level 6
Joined
Aug 1, 2009
Messages
159
Well, title says it all! I want to learn structs, I can't find a tutorial about structs. How do structs work?
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
er...

to actually understand how structs work, first you need to understand basic collections like stacks, queues, dequeues, and lists in general.

http://www.hiveworkshop.com/forums/...array-linked-list-stack-queue-dequeue-188528/

Then look at this (code in plain JASS, vJASS works the same way but has extra stuff)
JASS:
private integer instanceCount = 0
private integer array stackRecycler

JASS:
function CreateInstance takes nothing returns integer
    local integer this

    if (stackRecycler[0] == 0) then
        //increase the counter (ensure unique instances)
        set this = instanceCount + 1
        set instanceCount = this
    else
        //pop last recycled instance off the stack
        set this = stackRecycler[0]
        set stackRecycler[0] = stackRecycler[this]
    endif

    return this
endfunction

JASS:
function DestroyInstance takes integer this returns nothing
    //push on the stack
    set stackRecycler[this] = stackRecycler[0]
    set stackRecycler[0] = this
endfunction

As simple as that. Just try to read the logic behind it.

Next, you'll want to check this out for my argument on why to build structs from scratch rather than use vjass structs.

http://www.hiveworkshop.com/forums/...ls-280/coding-efficient-vjass-structs-187477/

Then you'll need to learn about delegates and modules =).

JASS:
//a struct that generates 0 code in the background
struct A extends array
endstruct

//a struct that generates lots of code in the background (create, destroy, allocate, etc)
struct A
endstruct

//a function that goes into a struct and automatically takes the this argument of
//the struct type (integer)
method hello takes nothing returns nothing
//is
function hello takes integer this returns nothing

//a method that doesn't take the this argument
static method hello takes nothing returns nothing
//is
function hello takes nothing returns nothing

When a variable is of a specific type (struct type), then it can act as a pointer for that struct. Pointers are just indexes to arrays. For example, if a struct had a field public integer h and there was a variable MyStruct i, then you could do set i.h = 5.

JASS:
struct MyStruct extends array
    public integer h
    //is
    //integer array h (within the scope of MyStruct)
endstruct

function Hello takes nothing returns nothing
    local MyStruct i = 0 //a plain integer, but can act as a pointer to MyStruct arrays
    set i.h = 5 //(set h[i] = 5, where the h is of MyStruct)
endfunction

A static integer within a struct would just be a plain integer and could be accessed by the actual struct name-
JASS:
struct MyStruct extends array
    public static integer h
    //is
    //integer array h (within the scope of MyStruct)
endstruct

function Hello takes nothing returns nothing
    local MyStruct i = 0 //a plain integer, but can act as a pointer to MyStruct arrays
    set i.h = 5 //(set h = 5, where the h is of MyStruct)
    set MyStruct.h = 5 (//also works since it doesn't require an index)
endfunction

You can also have a public static integer array within a struct.

From here, you can use the public and private access modifiers.

Delegates can also be used for inheritance and pointing to other structs.
JASS:
struct A extends array
    public method bleh takes nothing returns nothing
    endmethod
endstruct
struct B extends array
    private delegate A a //a delegate of type A, my syntax may be wrong here since I don't use them often)
endstruct

function DoSomething takes nothing returns nothing
    local B b = 3
    call b.bleh() //calls A(3).bleh(), or bleh(3) due to the delegate. Will only call it if the method doesn't already exist
                    //in the original struct, in this case B.
endfunction

You can also tell the parser what struct to treat an integer as.

B(3) would typecast 3 to the B type.
-> call B(3).bleh()

You can also do it with variables
->call A(b).bleh()

Remember that struct variables are just integers that act as pointers. They point to specific indexes of the arrays of that struct and are passed in to every non-static method so that it knows which indexes of the arrays to use =P.

In this way, struct values don't collide with each other (every instance is unique). Take another look at the create and destroy code to see how the instances will always end up being unique.
 
I think Nestharus ruined it for you x)

Basicly, a struct is an object :D

In warcraft III, there is a ... "struct" (It's a class actually but I don't want to get into that :p) that defines what a "Unit" is:

It would look something like this:
JASS:
struct unitdata
    integer handleid
    integer uid
    real x
    real y
    real life
    real mana
    real maxlife
    real maxmana
    real facing
endstruct

This "object" has data stored in it :)
You can create a new "object" and give it its own data.

This is great for spells ^^

There are also functions for structs:

Static methods & methods

The difference is that static methods need you to give an instance of the struct so
it knows what object you're talking about :p

Luckily, struct instances (thistype) are exactly like integers ^^

Methods are the same, but you have to give it an instance outside the function:

(Assume the presence of the above struct)
JASS:
function action takes nothing returns nothing
    local unitdata ud = unitdata.create() // We call a create function when we want to create an "object". There's also an .allocate() function that we use inside the struct if we want to add a "custom" create static method
    set ud.uid = 'u001'
    // ... bla bla bla
    // If there's a "method" (not static) you call something like this:
    call ud.somemethod
    // If it's static:
    call unitdata.somemethod
endfunction

Nestharus can explain modules and interfaces :) (I only work with basic structs)
 
If you use plain vJASS structs, you could be flooded with triggers and trigger evaluations.

What if I want to D: xD
I don't use structs that are THAT basic
I started writing spells that have this general format:

JASS:
scope Spell initializer Init

    globals
        private constant integer ABIL_CODE = 'A000'
    endglobals

    struct Data
        // some variables
        // ..
        // ..
        // ..

        static method dmg takes nothing returns nothing
        endmethod

        static method filter takes nothing returns boolean
        endmethod

        static method expire takes nothing returns nothing
            // for timer loops
        endmethod

        static method create takes nothing returns thistype
            // bla bla bla bla
        endmethod

        method onDestroy takes nothing returns nothing
        endmethod

    endstruct

    private function Action takes nothing returns nothing
        // create struct
        // do some actions
        // start timer
    endfunction

    private function Cond takes nothing returns boolean
        return GetSpellAbilityId()==ABIL_CODE
    endfunction

    private function Init takes nothing returns nothing
        local trigger t = CreateTrigger()
        // register event
        // register condition
        // register action
        set t = null
    endfunction
endscope
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
Never use onDestroy : |... also, what's up with the scope??

try this format instead-
JASS:
struct Spell extends array
    private static integer ic = 0
    private static integer array ir

    static method create takes nothing returns thistype
        local thistype this

        if (ir[0] == 0) then
            set this = ic + 1
            set ic = this
        else
            set this = ir[0]
            set ir[0] = ir[this]
            debug set ir[this] = -1
        endif

        return this
    endmethod

    method destroy takes nothing returns nothing
        debug if (ir[this] == -1) then
            set ir[this] = ir[0]
            set ir[0] = this
        debug endif
    endmethod

    private static method run takes nothing returns nothing
        
    endmethod

    private static method onInit takes nothing returns nothing
        local trigger t = CreateTrigger()
        call TriggerAddAction(t, function thistype.run)
        set t = null
    endmethod
endstruct
 
Level 6
Joined
Aug 1, 2009
Messages
159
Thanks for pointing that out. I'm going to try and make a struct stored an object or something like that. So basically I'm going to do this:

JASS:
struct data
    integer id
    unit u //cast
    real x 
    real y
//and so on,.....

I'm starting out small I don't wanna move to advance right away. So please bare with me,

So after I make struct "data" I make another function to call those variable-like thingy inside the struct? How do I make them? is it structname.variable?

So:

JASS:
function actions takes nothing returns nothing
    local data d = unitdata.create() 
    set d.id = 'H001'
    //actions for spell.
endfunction

Like that?? And what are method and statics? The one Magtheridon96 talking about? May you give me a simple example of using your way (shown above)? Cause I'm pretty much getting it.

And I have 1 more question to you Magtheridon, why use that (structs) instead of globals? I think they work the same way? Since I store data and call it to another function.

As for you Nestharus, I know your a good coder. But its kinda hard for me to understand. What is your private integer instantCount = 0 and private integer array stackRecycler?

Why will you need to recycle that? :\. As for the links you gave me, I will look on them ASAP and see if I can understand more about yours. :D

+rep
 
I'm starting out small I don't wanna move to advance right away. So please bare with me,

It's all cool ^-^

So after I make struct "data" I make another function to call those variable-like thingy inside the struct? How do I make them? is it structname.variable ?

When you give a struct a variable, if it's not static, you call it instancename.variablename

The instance name would be the "data" in this case:
JASS:
function blekh takes nothing returns nothing
    local somestruct data = somestruct.create()
    // It has a unit variable called "u" in it
    set data.u = GetTriggerUnit()
    // if it was "static" (like in the case Nestharus gave):
    set somestruct.u = GetTriggerUnit()
    // WARNING: Logically, stuff like the "caster" in a struct should NEVER be static
    // Static means constant/nonchanging
endfunction

You get it now? :)

Also:

JASS:
function actions takes nothing returns nothing
    local data d = unitdata.create() 
    set d.id = 'H001'
    //actions for spell.
endfunction

-> Should be:

JASS:
function actions takes nothing returns nothing
    local unitdata d = unitdata.create() 
    set d.id = 'H001'
    //actions for spell.
endfunction

-----------------------------


why use that (structs) instead of globals

Because globals have ONLY ONE instance.
When you create a struct, you're creating a whole new set of variables for a spell :)
Also, in structs, you can have functions (static methods and methods) that you can
use to "handle" the instances of the struct.

JASS:
struct SpellData
    unit caster
    real x
    real y
    
    static method create takes nothing returns thistype
        local thistype this = thistype.allocate // A "thistype" is an instance
        set this.caster = GetTriggerUnit()
        set this.x = GetUnitX(this.caster)
        set this.y = GetUnitY(this.caster)
        return this
    endmethod
endstruct

In this case, using "SpellData" instead of "thistype" is just about the same :p

As for you Nestharus, I know your a good coder

Pffffffffffffffffffffffffffffffffffffffffffffffft
 
Level 6
Joined
Aug 1, 2009
Messages
159
When you give a struct a variable, if it's not static, you call it instancename.variablename

What if, its static? Do I use the same thing?

-> Should be:

JASS:
function actions takes nothing returns nothing
    local unitdata d = unitdata.create() 
    set d.id = 'H001'
    //actions for spell.
endfunction

Ooh, unitdata is a variabletype, sorry 'bout that. :D.

------------------------------------------------------------

So what about others? I saw, Call PauseTimer(???) what are those for? Loops/Instances? I wanna learn about 'em.
 
basically static members are members that is only created once per struct, and not per struct instance, meaning if you change it in one instance, it also affects any other instance... its the same as a non-array global variable...

JASS:
struct A
    
    static integer b = 0
    integer c = 0

    method change takes nothing returns integer
          set A.b = A.b + 1
          return A.b
          //not sure if the variable "this" works with static members...
    endmethod
    
    method changec takes nothing returns integer
          set this.c = this.c + 1
          return this.c
    endmethod

    method loop takes nothing returns nothing
          local A data = 1
          call BJDebugMsg(I2S(data.Change))
          //will show 1
          call BJDebugMsg(I2S(data.Changec))
          //will show 1
          set data = 2 //changes the instance
          call BJDebugMsg(I2S(data.Change))
          //will show 2 even if we changed instances
          call BJDebugMsg(I2S(data.Changec))
          //will show 1 since we changed instance
    endmethod
     
endstruct
 
Status
Not open for further replies.
Top