How to tell if a unit is already in a struct instance?

NeuroToxin

New Member
Reaction score
46
As the title says, I want to know how to tell if a unit is already associated with another struct instance of the same type.
 

Weep

Godspeed to the sound of the pounding
Reaction score
400
You will need to somehow associate that struct with the unit, eg. by saving its integer in a hashtable at the unit's handle ID, or in an array at the unit's custom value (if using a unit indexer like AIDS). Then, you can see if a struct is attached to the unit because there will be a value. (Don't forget to clear it/set to 0 when destroying the struct!)

Alternately, the struct itself could be made to extend array, and using a unit indexer, the struct can be made to have the same index as the unit, so there will always only be 1 instance per unit because you designed it that way. :)
 

Bo-Bo

New Member
Reaction score
8
Store the structs in an array, then do something like this:

JASS:
static method isUnitInArray takes unit u returns boolean
  local thistype this
  local integer i = 0
  local boolean check = false
  
  loop
    exitwhen (check or (i >= STRUCT_COUNT))

    set this = STRUCT_ARRAY<i>
    if (.u == u) then
      set check = true
    endif
    
    set i = i + 1
  endloop

  return check
endmethod</i>

".u" being of course a member of your struct.

That's the way I do it, but of course there are tons of better ways.
And I'd be glad to learn them. =)
 

NeuroToxin

New Member
Reaction score
46
What im trying to do, is get it so every dummy unit is associated with its caster. EX. When a unit dies, I have a passive that is going to send it to the unit, then make it circle around the unit. However, when I want to select a random unit frmo there, I cannot do (units owned by (triggering unit)) Therefore, I need to find a way to associate the dummy units with a certain unit. I am fully against hashtables as they confuse me.
 

tooltiperror

Super Moderator
Reaction score
231
Hash tables are about as complicated as you let them be.

It's a 2D array. You can throw in some extra function calls and fancy handle magic, but a hash table is simply a special array.
 

Weep

Godspeed to the sound of the pounding
Reaction score
400
What im trying to do, is get it so every dummy unit is associated with its caster.
I'd add the dummies to a unit group member of a struct attached to the caster...or, in semi-GUI language, a unit group array keyed to the custom value of the caster as assigned by a unit indexing system.
 

chobibo

Level 1 Crypt Lord
Reaction score
48
Use a unit indexing system, since all units have a unique Id assigned to it, structs instances would be assinged to a uniqe unit id as well.

consider the following example:
JASS:

function sample takes nothing returns boolean
    local integer id=GetUnitIndex(X)
    local structA A=A(id)
    local structB B=B(id)
endfunction

when you create a structA or structB's instance, both of them will use the same id, hence we may say that structA and structB's instance is attached to unit X.
Of course, implementation of the said script would be different, or should be added to the structs create method.
 

luorax

Invasion in Duskwood
Reaction score
67
Use Vexorian's Table. Then do something like this: (Handwritten!)

JASS:
struct ABC
    
    unit Owner
    
    private static HandleTable table

    static method create takes unit u returns thistype
        local thistype this = 0
        
        if thistype.table.exists(u) then
            return thistype(thistype.table<u>)
        endif

        set this = thistype.allocate()
        set this.Owner = u
        set thistype.table[this.Owner] = this
        return this
    endmethod

    method destroy takes nothing returns nothing
        call thistype.table.flush(this.Owner)
        set this.Owner = null
        call this.deallocate()
    endmethod

    static method getInstance takes unit u returns thistype
        return thistype(thistype.table<u>)
    endmethod

    private static method onInit takes nothing returns nothing
        set thistype.table = HandleTable.create()
    endmethod

endstruct</u></u>
 

Romek

Super Moderator
Reaction score
964
You could make a static group in the struct. When a unit becomes associated with an instance, add the unit to the group. When the object is destroyed, remove the unit from the group.
Then simply use [ljass]IsUnitInGroup[/ljass]. If you're using an sort of unit indexing system, it'd probably be a safer bet to use that to attach the boolean instead.

Don't loop through every instance of the struct. There are far better ways of accomplishing what you want.
 

Sevion

The DIY Ninja
Reaction score
413
As Romek says, don't loop through every instance of the struct... That's very, very inefficient. As bad as it can get.

You guys are making this as complicated as you can, aren't you? D:

JASS:
struct myStruct
    // ... blah blah blah ...

    public static hashtable hash
    public unit whichUnit

    public static method has takes unit whichUnit returns boolean
        return (LoadInteger(thistype.hash, GetHandleId(whichUnit), 0) != 0 or not HaveSavedInteger(thistype.hash, GetHandleId(whichUnit), 0))
    endmethod

    public static method create takes unit whichUnit returns thistype
        local thistype this
        
        if (LoadInteger(thistype.hash, GetHandleId(whichUnit), 0) != 0 or not HaveSavedInteger(thistype.hash, GetHandleId(whichUnit), 0)) then // Second part may not be necessary. I don&#039;t remember
            set thistype.whichUnit = whichUnit
            call SaveInteger(thistype.hash, GetHandleId(whichUnit), 0, this)
        else
            debug call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, &quot;Warning: Unit already identified with an instance!&quot;)
            return 0
        endif
        // ... blah blah blah ...
        return this
    endmethod

    private method onDestroy takes nothing returns nothing
        call RemoveInteger(thistype.hash, GetHandleId(this.whichUnit), 0)
        set this.whichUnit = null
    endmethod

    private static method onInit takes nothing returns nothing
        set thistype.hash = InitHashtable()
    endmethod
endstruct

function trololol takes unit whichUnit returns nothing
    local myStruct lolol

    if ( not myStruct.has(whichUnit) ) then
        set lolol = myStruct.create(whichUnit)
    endif

    // ... blah blah blah ...
endfunction
 

chobibo

Level 1 Crypt Lord
Reaction score
48
You guys are making this as complicated as you can, aren't you?
You're doing the same too.

First of all, the linear search is bad lol.

The group check is simple to implement, but you'll need 1 group handle per struct or per spell with the same properties. The algorithm for checking the units inside the group is hidden, but I believe it's efficient enough.

The Hashtable, while also simple to implement, suffers from the same problem (1 hash table per struct or spell, as suggested by your code). Vexorian's Table on the other hand does not, since it uses a single hashtable.

A unit indexing system could handle multiple structs, it could even replace the struct initializer if done properly. But its not without a disadvantage, implementation is a pain in the ass.

All of these solutions have strongpoints and disadvantages, so it really depends to NeuroToxin's map, if the solution would conflict or not in his project.

The problem at hand is also not as simple as you think it is.

No offence man! :D Just trying to give an opinion.
 

Sevion

The DIY Ninja
Reaction score
413
I think you're misunderstanding my code.

The 1 hashtable per struct/spell is for handling collisions o_O'

(I.E. two different structs instanced to the same unit would overwrite each other unless you had two hashtables OR, read below)

And there'd be a way to make it 1 global hashtable. Simply instead of saving the data at 0, save it at a key for each struct.

I simply don't like Table. However nice it probably is, I don't like it. Never had to use it.
 

chobibo

Level 1 Crypt Lord
Reaction score
48
I did understand, I just wanted to point out the way you are trying to do it. Whenever you want to attach a struct to a unit, you'd need to use 1 hashtable, and we all know wc3 engine suck at handling large amount of handles. Like you said, it's possible to just use a single hashtable for it, but of course it depends on the one putting the scripts in the map to handle those public handles, and that makes the said solution unportable, but possible. :D

I also haven't used hashtables, we'll because I never do anything, just some random scripts lol.
 

Sevion

The DIY Ninja
Reaction score
413
Truthfully, I would rather handle the hashtable myself than have an indexing system or other do it. There's less overhead when I do it.
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top