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

[vJASS] Arrays in structs problem

Status
Not open for further replies.
Level 9
Joined
Aug 26, 2010
Messages
573
Hey guys, I have a problem - my sturct HeroClass has array fields:
JASS:
integer array abilities[4]
integer array abilityLearners[4]
integer array abilityLearnerContainers[4]
And every instance uses same arays. I mean - if h1 and h2 are HeroClass instances h1.abilities[1] will be always equal to h2.abilities[1]
here is definition of this struct
JASS:
public struct HeroClass //Hero class struct
    HeroStats hsBase
    HeroStats hsGrowth
    integer iUnitTypeId = 0
    
    integer iAbilities
    integer array abilities[4]
    integer array abilityLearners[4]
    integer array abilityLearnerContainers[4]
    
    private static integer instance = 0
    
    static method create takes nothing returns thistype
      local thistype hcTemp
      set instance = instance + 1
      set hcTemp = instance
      
      set hcTemp.hsBase = HeroStats.create()
      set hcTemp.hsGrowth = HeroStats.create()
      
      return hcTemp
    endmethod
endstruct
 

LeP

LeP

Level 13
Joined
Feb 13, 2008
Messages
537

Nope, that won't help at all.
The efficiency does not matter at all. Then, that thing would have the same problem like the one from the op. That is, overwriting array-member.
But only if you could actually have array-member inside of an array-struct.
Not to mention all the things that wont work if you use array-structs or custom allocate/destroy-methods (i already posted them somewhere).

And you'd have to type the same shit over and over again.

It's one of the worst options available.
 

LeP

LeP

Level 13
Joined
Feb 13, 2008
Messages
537
I suggest that you use hashtable instead of array members for the struct.

Look, there are multiple workarounds. But they are still workarounds.
Workarounds for a problem you introduced yourself.
The simplest and cleanest and easiest ways is to just use structs with damn array-members.
 
or use Bribe's Table... by the same reason that Starquizer said above... And I think you can actually make the table a static or a global in that case since I don't think you would register the same hero more than once...

@LeP - you already said, workarounds are workarounds... There's no problem in suggesting other workarounds right?
 
Level 9
Joined
Aug 26, 2010
Messages
573
I am just suggesting, as there are size limit for those arrays.

Lol, have u seen struct name? Yes, HeroClass. With array size 4 limitation on structs amount is still more then 2k. In fact the limit of summ amount equal to 8190 allows me to make 8190 spells for all classes. I think 10% is much more than I need :D

And I don't think array extended struct is a good solution here.
 
Level 10
Joined
Sep 19, 2011
Messages
527
Nope, that won't help at all.
The efficiency does not matter at all. Then, that thing would have the same problem like the one from the op. That is, overwriting array-member.
But only if you could actually have array-member inside of an array-struct.
Not to mention all the things that wont work if you use array-structs or custom allocate/destroy-methods (i already posted them somewhere).

And you'd have to type the same shit over and over again.

It's one of the worst options available.

I forgot to put : "... and use table by bribe". That happens when I make a quickly reply :ogre_hurrhurr:

It's one of the worst options available.

I consider it one of the best options. As you can see, you can save a lot of code by this way. Sure, also you lose the double free protection, but, if you're careful nothing happens :D
 
Level 9
Joined
Aug 26, 2010
Messages
573
It makes using very easy and code very readable. And I don't care about limits with this struct. You have to be mad man to make 8190 spells. And you will still have a 0 element free. And this system doesn't lags.
BUT. Of course, main thing is that it works here.
And by the way. If I'll have to change this I'll have to change almost all my skill system. There are more than 1000 lines of code writen by me alone at the moment. And making major changes in 200-300 lines will make me very-very sad. So I will not change this. At least now :p
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
why you using arrayed struct members btw?, others say that arrayed members are compiled incorrectly and I have the same problem with that >>> http://www.hiveworkshop.com/forums/2139560-post79.html

use hashtable or best TableArray...

It seems like an other troll about Jasshelper.
I've not used array members that much in vJass structs, but when i've tried it worked just fine.
Now there are two facts :

- arrays members are not going to work if you don't use the default struct allocators (so no struct extends array, anyway you're not allowed to use them in such structs)
EDIT : ofc you can still use custom ones if you handle them like the default allocators do, but there is no point to do it.
- because how it's compiled it would mess up if you go out of range, example you declare a member array with a size of 5 and then use the index 5, when you are supposed to use 0 to 4 included.
If you do that it's most likely you will conflict with an other struct instance.
 
Last edited:
Level 29
Joined
Mar 10, 2009
Messages
5,016
that troll would be Magtheridon96 (sorry mags), perhaps the reason for it not to
work is that struct is already an arrayed index when you allocate them, and
somehow there's a 'magic' that would mess that up...and if you read my
code in the link it uses arrayed members and does not go beyond the declared
500 index, still it doesnt work, the full code would be in http://www.hiveworkshop.com/forums/spells-569/fireescort-215372/?prev=status=p&u=mckill2009 but I've replaced that to TableArray...
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
@mckill2009 if you use an array member of 500, then you can only use only 16 instances of the struct simultaneously (8190/500), i suppose that's why you say it doesn't work.
If you need this amount and more than 16 instances, then yeah you need something else, but that doesn't mean that "arrayed members are compiled incorrectly", hell the limitation is even written in the vJass documentation, plus nothing forbids you to check the "resulted" jass code.

Arrayed member work correctly, they just have limitations, which are written in the documentation (excepted probably the behavior when you go out of range, but you can guess it if you check the compiled jass script)

@Adiktuz : That doesn't make sense, it all depends how many struct instances you need simultaneously at max.
 
Level 29
Joined
Mar 10, 2009
Messages
5,016
Without any providen code i'm not going to believe you (you probably don't care though)
oh I really do care :p...first cast is OK, the rest no even on T32...

JASS:
library FireEscort uses CTL

globals
    private constant integer           SPELL_ID = 'A002' //Howl of Terror(rawID)
    private constant integer     DUMMY_SPELL_ID = 'A000' //Firebolt(rawID)
    private constant integer           ORDER_ID = 852231 //Firebolt
    private constant integer           DUMMY_ID = 'h000' //rawID
    private constant integer            BOMB_ID = 'h001' //rawID
    private constant real              INTERVAL = 0.03125
endglobals

native UnitAlive takes unit u returns boolean

//! textmacro SE takes UNT
set x = GetUnitX($UNT$)
set y = GetUnitY($UNT$)
set angle = Atan2(y-yDum, x-xDum)
set distance = getDistance(x,y,xDum,yDum)
loop
    exitwhen index==maxbombs
    call SetUnitX(.d[index], xDum+.offset*Cos(.gap[index]))
    call SetUnitY(.d[index], yDum+.offset*Sin(.gap[index]))
    call SetUnitFlyHeight(.d[index], .flyheight, 0)
    set .gap[index] = .gap[index] + gapdist
    set index = index + 1
endloop
if distance > distancetoreach then
    call SetUnitX(.dummy, xDum+followspeed*Cos(angle))
    call SetUnitY(.dummy, yDum+followspeed*Sin(angle))
endif
//! endtextmacro

private function LoadFirst takes nothing returns nothing
    local unit u = CreateUnit(Player(15), DUMMY_ID,0,0,0)
    call UnitAddAbility(u, DUMMY_SPELL_ID)
    call KillUnit(u)
    set u = null
endfunction

private struct FE
    unit caster
    unit target
    unit dummy
    unit array d[1]
    real array gap[1]
    real duration
    real offset
    real search
    real flyheight
    player owner
    
    //Configurables:
    static integer maxbombs = 6
    static real rotationspeed = 1
    static real followspeed = 7
    static real gapdist = 1 //recommended for 6 bombs
    static real raisespeed = 2
    static real offsetspeed = 2
    static real maxoffset = 300
    static real aoe = 900
    static real searchinterval = 2
    static real maxheight = 400 //this should not be greater than your CAST RANGE
    static real maxduration = 60 //sets the life of the dummy captain
    static real distancetofollow = 640000 //SquareRoot is 800
    static real distancetoreach = 3600 //Squareroot is 60
    //==========
    
    method getDistance takes real x1, real y1, real x2, real y2 returns real
        return (x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)
    endmethod
    
    method filterThem takes unit caster, unit target returns boolean
        return UnitAlive(target) and IsUnitEnemy(caster,GetOwningPlayer(target)) and not (IsUnitType(target, UNIT_TYPE_STRUCTURE) and /*
        */ IsUnitType(target, UNIT_TYPE_MECHANICAL) and IsUnitType(target, UNIT_TYPE_MAGIC_IMMUNE))
    endmethod
    
    implement CTL
        local unit first
        local real x
        local real y
        local real xDum
        local real yDum
        local real angle
        local real distance
        local real distance2
        local integer index
        local integer dumID
    
    implement CTLExpire
        set index = 0
        set dumID = GetHandleId(.dummy)
        if UnitAlive(.caster) and .duration > 0 then
            set .duration = .duration - INTERVAL
            set xDum = GetUnitX(.dummy)
            set yDum = GetUnitY(.dummy)
            
            if .offset < maxoffset then
                set .offset = .offset + offsetspeed
            endif
            
            if .flyheight < maxheight then
                set .flyheight = .flyheight + raisespeed     
            endif
            
            if .target==null then
                //! runtextmacro SE(".caster")
                set .search = search + INTERVAL
                if .search > searchinterval and distance < 4000 then
                    call GroupEnumUnitsInRange(bj_lastCreatedGroup,xDum,yDum,aoe,null)
                    loop
                        set first = FirstOfGroup(bj_lastCreatedGroup)
                        exitwhen first==null
                        if filterThem(.caster, first) then
                            set .target = first 
                        endif
                        call GroupRemoveUnit(bj_lastCreatedGroup, first)
                    endloop
                    set searchinterval = 0
                endif
            else
                if UnitAlive(.target) then
                    //! runtextmacro SE(".target")
                    if .flyheight >= maxheight then
                        set distance2 = getDistance(GetUnitX(.caster),GetUnitY(.caster),xDum,yDum)
                        if distance2 < distancetofollow then
                            set index = 0
                            loop
                                exitwhen index==maxbombs
                                call IssueTargetOrderById(.d[index],ORDER_ID,.target)                    
                                set index = index + 1
                            endloop
                        else
                            set .target = null
                        endif
                    endif
                else
                    set .target = null
                endif
            endif
        else //End the Spell
            call KillUnit(.dummy)
            loop
                exitwhen index==maxbombs
                call KillUnit(.d[index]) 
                set .d[index] = null
                set index = index + 1
            endloop
            set .caster = null
            set .target = null
            set .dummy = null
            call .destroy()
        endif
    implement CTLEnd 
    
    static method setup takes unit u, player p returns nothing
        local thistype this = create()
        local integer lvl = GetUnitAbilityLevel(u, SPELL_ID)
        local integer index = 0
        local real g = 0
        local integer dumID
        set .caster = u
        set .target = null
        set .duration = maxduration
        set .owner = p
        set .dummy = CreateUnit(p,DUMMY_ID,GetUnitX(u),GetUnitY(u),0)
        set .offset = 0
        set .flyheight = 0
        set .search = 0
        set dumID = GetHandleId(.dummy)
        loop
            exitwhen index==maxbombs
            set .d[index] = CreateUnit(p,BOMB_ID,0,0,0)
            set .gap[index] = g
            call SetUnitFlyHeight(.d[index], 0,0)
            call UnitAddAbility(.d[index], DUMMY_SPELL_ID)
            call SetUnitAbilityLevel(.d[index],DUMMY_SPELL_ID, lvl)
            set g = g + gapdist
            set index = index + 1
        endloop  
    endmethod 
    
    static method cast takes nothing returns boolean
        if GetSpellAbilityId()==SPELL_ID then
            call setup(GetTriggerUnit(), GetTriggerPlayer())
        endif
        return false
    endmethod   
    
    static method onInit takes nothing returns nothing
        local trigger t = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
        call TriggerAddCondition(t, function thistype.cast)
        call LoadFirst()
        set t = null
    endmethod   
endstruct

endlibrary


The one working is in the spell's section with TableArray implemented...http://www.hiveworkshop.com/forums/spells-569/fireescort-215372/
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
@mckill2009 :
Your array size is just equal to 1, when it should be equal to maxbombs at least.
Array member size inside a struct is not dynamic like a normal array variable, it's static, you have to define the size correctly.
That's why you overwrite.
 
Last edited:
Level 17
Joined
Apr 27, 2008
Messages
2,455
Well, i can judge only what i see and you say and here the array size is obviously not enough.
And by static, i talked about the array size (like with Galaxy of sc2, or the C language if you prefer).
Plus, you said it didn't work neither with T32.
I mean here the error is obvious, it is the array size.

yourself said:
first cast is OK, the rest no even on T32...
 
Level 29
Joined
Mar 10, 2009
Messages
5,016
Plus, you said it didn't work neither with T32.
sorry, the T32 I was talking about post#14, array is 500, not 1...and the
array size is fine and should be static or a global one coz you can only change
that in the allocation, like indexing in GUI...
JASS:
.d[0]
.d[1]
.d[2]
//etc...
anyway forget this topic as I cant seem to find a solution for this using CTL...
 
They aren't compiled incorrectly, they just compile into shit.
There are multiple solutions:

1- Fake 2D Arrays:

array[size * this + index]

2- Hashtable:

JASS:
hashtable hash = InitHashtable()

Save(hash, this * numberOfArrayVariables + variableNumber, index, value)
Load(hash, this * numberOfArrayVariable + variableNumber, index)

3- Tables:

JASS:
Table array1
Table array2

set array1 = Table.create()
set array2 = Table.create()

this.array1[index] = value
this.array2[index] = value
 
Level 9
Joined
Aug 26, 2010
Messages
573
For me there is no diffence what it is compiled to while it is compiled correctly and until it won't make map lagging. And before alfa release I won't know that it is laggy because of imbPC ^^ Then if system made like this will lag I will make something more effective.

Btw i thought they (arrays in struct) are comiled in pseudo-2d arrays, am I wrong?
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
Magtheridon96 said:
They aren't compiled incorrectly, they just compile into shit.

No, as many other vJass features, it's just not for speedfreaks.
However it could still be faster than using an hashtable. (not tested and i don't bother to do it)
The api is way neater at very least than using an hashtable or even a Table.

Now, sure they have limitations and cons, but it's totally bullshit to say that "they just compile into shit" or "they compile incorrectly".

vJass was not, is not, and will never be for speedfreaks.
The main point of this jass preprocessor is to make easier to write jass, sure it's far from perfect and you can hijack it in many ways, but it is not the standard.
 
Status
Not open for further replies.
Top