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

Using a struct in Jass/GUI

Status
Not open for further replies.

Ardenian

A

Ardenian

I read this thread with great interest.
So appearently I can create a struct in GUI and Jass using global variables.
However, I don't understand how.

Example: PlayerID.Index.UnitID

Under each player ID, save Unit IDs under an index:
1.1.Unit A ID
1.2.Unit B ID
1.3.Unit C ID
for every player:
2.1.Unit D ID
(...)

However, I am not sure how I can translate this to Jass and GUI now, using globals.

I would be glad to receive some starting help.
 

Chaosy

Tutorial Reviewer
Level 40
Joined
Jun 9, 2011
Messages
13,183
While I guess you could do it in the GUI..

I am not sure about the benefits for GUI uesers though, I mean it wont exactly be GUI friendly for those who try to use a system which requires this, and otherwise you might as well use vjass.

What's your goal? edit: nvm that, I let me think for a sec..

edit2: okay I think I can do that fairly easily is it what you want though or is it just an example?
 

Ardenian

A

Ardenian

Okay, I had another look on that thread, seems one reverses it:

PlayerID.Index.UnitID
-> Set udg_Unit[Index[Player ID]] = Unit N's ID

Is this the correct approach ?
I thought a bit about it, but I am not sure whether that's the correct approach.

If you dislike the term 'struct' replace it with 'stacked array'.
 

Ardenian

A

Ardenian

I am trying to avoid having different globals:
Unit1[array] for player X
Unit2[array] for player X
Unit3[array] for player X
(...)

Instead of these different globals I hope for a way to use stacked arrays.
 
Level 22
Joined
Feb 6, 2014
Messages
2,466
I have a feeling what you want to achieve can be done with 2d arrays. Example:
PlayerHero[PlayerId*4 + 1] = 1st Hero
PlayerHero[PlayerId*4 + 2] = 2nd Hero
PlayerHero[PlayerId*4 + 3] = 3rd Hero
PlayerHero[PlayerId*4 + 4] = 4th Hero
But the disadvantage is, you have to know the maximum amount of "Hero" per player.
 

Chaosy

Tutorial Reviewer
Level 40
Joined
Jun 9, 2011
Messages
13,183
You could do this:
JASS:
//! zinc
    library x
    {
        struct User
        {
            unit x[999];
			integer count = 0;
            
			method u(integer i) -> unit
			{
				return x[i];
			}
			method add(unit tU)
			{
				x[count] = tu;
				count += 1;
			}
			
            static method create() -> thistype
            {
                thistype this = thistype.allocate();
                return this;
            }
        }
        
        function onInit()
        {
            User p1 = User.create(); //this should be a global and not a local
			h.add(CreateUnit(Player(0), 'hpea', 0, 0, 0);
            BJDebugMsg(I2S(h.u(0)));
        }
    }
//! endzinc

And then use p1.u(number)
or p1.x[number]

For your GUI needs you could make a trigger with this and run that trigger each time you want to get a unit.
I didn't bother to make this dynamic since it's just for showcase anyway.
 

Ardenian

A

Ardenian

Ah I see, thank you guys, I try to do it with a 2D array.

Though, how do stacked array work ?

Example:

Value 1
Value 2 Value 3 Value we need

1
1 11

2
22 2

3
33 3

I have this list, 2.2.2.2 for example.

When I use array, then it would be Set Searchedvalue = Value3[Value2[Value1]]
wouldn't it ?
2 = 1[1[2]]

However, how do I set the values except the final array ?
Value3[Value2[Value1]]

No matter what value I insert for Value1, how can I define Value2 and Value3 properly ?
 
Level 24
Joined
Aug 1, 2013
Messages
4,657
A struct is simply a way to do object generation and data structures.

If you read a thread about dynamic indexing, you got the entire thing already.
The only difference is that structs are more readable and easier to code because there is less room for mistakes.

If you want to simulate structs, simply make arrays of variables:
JASS:
struct Object
    public real x
    public real y
    
    public method setPosition takes real x, real y returns nothing
        set .x = x
        set .y = y
    endmethod
endstruct
=>
JASS:
globals
    real array s_Object_x
    real array s_Object_y
endglobals

function s_Object_setPosition takes integer this, real x, real y returns nothing
    set s_Object_x[this] = x
    set s_Object_y[this] = y
endfunction

Structs just have an allocation and deallocation method by default, so you wont have to worry about collisions.
You also dont have to think about how 2d arrays kinda work.
You also can make use of polymorphism (object inheritance mostly).
You also dont have to care about a prefix in variables and functions.
And many more things.

It is also good practise because in other languages, everything is based on object oriented programming... except one rebel: Javascript.
 

Ardenian

A

Ardenian

Thank you Wietlol, could you give me a more complex example, please ?
I tried to create a few, but I struggle doing so.
How would, for example, look a simulated struct with more than one dot, sth.sth.sth ?
 
Level 24
Joined
Aug 1, 2013
Messages
4,657
That doesnt matter.
The multiple dots are multiple structs:

JASS:
struct FinalObject
    
    public unit ref
    
endstruct

struct OtherObject
    
    public FinalObject fobj
    
endstruct

struct Object
    
    public OtherObject oobj
    
endstruct

function foo takes nothing returns nothing
    local Object obj = Object.create()
    
    call RemoveUnit(obj.oobj.fobj.ref)
endfunction

How it works can simply be split up in different parts:
JASS:
function foo takes nothing returns nothing
    local Object obj = Object.create()
    local OtherObject oobj
    local FinalObject fobj
    local unit ref
    
    set oobj = obj.oobj
    set fobj = oobj.fobj
    set ref = fobj.ref
    call RemoveUnit(ref)
endfunction

function foo takes nothing returns nothing
    local integer obj = s_Object_create()
    local integer oobj
    local integer fobj
    local unit ref
    
    set oobj = s_Object_oobj[obj]
    set fobj = s_OtherObject_fobj[oobj]
    set ref = s_FinalObject_ref[fobj]
    call RemoveUnit(ref)
endfunction

But let me ask you a question: what is the reason to not use structs?
 

Ardenian

A

Ardenian

Thank you!

I would like to understand them in written Jass.
I do understand it is like a directory when browsing a system's foulder,
but when it comes to entering values in Jass using array variables I am a bit clueless.

In your second example, the second function, that's a good example for me.
Here you set the different struct parts to a value using locals.

However, where are the values here ?
JASS:
call RemoveUnit(obj.oobj.fobj.ref)

I do not understand how it can work without having concret values for everything.
As I am not very familiar with vJass, I might miss a point.
Does
JASS:
struct FinalObject
   
    public unit ref
   
endstruct
defines the value of a struct member ?
That's the same like
JASS:
set ref =
?
 

Ardenian

A

Ardenian

In vJass, yes, but in plain Jass ?

Excuse, my last question should have been:
'That's the same like set ref = when not using Jass ?'
 

Ardenian

A

Ardenian

set ref[ref2[x]] =

I think.
^This is exactly what I do not understand.
I do understand what it means, but not why it would work.

Example:
ref[ref2[x]] = 5

Now this term is equal 5.
But how do I define ref[(...)] ?
x is a value, ref2[x] is directly related to the value x,
but I cannot see any definition for ref[(...)].

Example2:

x = 2
ref2[2] = 5

But what is ref[(...)] now ?
Is it simply 5, as ref[ref2[2]] == ref[5] ?

But what if I would like to define it the other way around,
changing ref[(...)] and not the end of the directory, as in
2.0.0
3.0.0
?

I think I miss something.
 

Chaosy

Tutorial Reviewer
Level 40
Joined
Jun 9, 2011
Messages
13,183
Well it's certainly harder than I thought. In vjass you can use 2D arrays which might be good enough for you.

Basically you do: u[playerId][index] instead of u.playerId.index
A 2D array is basically an array of an array so it should be doable in pure jass as well but I could not figure out how.

I made a GUI example:
  • Melee Initialization
    • Events
      • Map initialization
    • Conditions
    • Actions
      • Unit Group - Pick every unit in (Units owned by Player 1 (Red)) and do (Actions)
        • Loop - Actions
          • Set tu = (Picked unit)
          • Custom script: set u[GetPlayerId(GetOwningPlayer(udg_tu))][udg_count] = udg_tu
          • Set count = (count + 1)
      • Set p = 0
      • Set i = 1
      • Custom script: set udg_tu = Id2Unit(udg_p, udg_i)
      • Game - Display to (All players) the text: (Name of tu)
      • Custom script: endfunction
      • Custom script: globals
      • Custom script: unit array u [12][99]
      • Custom script: endglobals
      • Custom script: library wtf
      • Custom script: function Id2Unit takes integer p, integer id returns unit t
      • Custom script: return u[id]
      • Custom script: endfunction
      • Custom script: endlibrary
      • Custom script: function x takes nothing returns nothing
Half of the script could be done in another trigger but hey..
This indexes all units owned by player 1 and then writes out the one at position 1 for player 1.
In my case it wrote "knight"
You could skip the function and directly use the 2D array but that's slightly more annoying.
 
Last edited:

Ardenian

A

Ardenian

Ahhh, that's a good example, thank you!

Just wondering, did someone already create a snippet for dynamic 2D array indexing ?
 

Ardenian

A

Ardenian

Hm, I see, thank you.

Alright, your example:
PlayerHero[PlayerId*4 + 1] = 1st Hero
PlayerHero[PlayerId*4 + 2] = 2nd Hero
PlayerHero[PlayerId*4 + 3] = 3rd Hero
PlayerHero[PlayerId*4 + 4] = 4th Hero

But what if I would extend the total heroes to 5 now ?
Would I simply do
set PlayerHero[PlayerId*5 + 1] = PlayerHero[PlayerId*4 + 1]
and so on, manually replacing everything ?
 
Level 22
Joined
Feb 6, 2014
Messages
2,466
You would have used PlayerHero[PlayerId*5 + 1] instead. So yeah manually replacing everything.
So example, Player2's 3rd hero is PlayerHero[2*5 + 3].
Player5's 4th hero is PlayerHero[5*5 + 4].
Of course you can make it so that Player1's id is 0 (Player3's id is 2 and so on) just like what GetPlayerId do.
You could always store it in a variable like MAX_HERO_COUNT. So in your implementation, you would use PlayerHero[PlayerId*MAX_HERO_COUNT + 1]
 
Status
Not open for further replies.
Top