[Snippet] Simple Unit Indexer

Codes & Snippets

13 years
edited 8 years
Description


This library aims to provide a simple way to attach data to units via unit indexing. It offers the minimal functions required to work. This library is the result of thinking about this proposal.

Requirements:


- Alloc 2

Actual Code

Code (jass) Select
/******************************************************************
*                    SIMPLE UNIT INDEXER V1.3                     *
*                           By moyack                             *
*                              2012                               *
*              ===================================                *
*              Exclusive resource from wc3jass.com                *
*              ===================================                *
******************************************************************/
library UnitIndexer initializer init requires Alloc
/*
  PURPOSE: Index units for easy attacking data to them
 
  FUNCTIONS:
   - GetUnitIndex: Takes a unit and returns its index (integer)
   - GetIndexUnit: Takes an integer and returns the unit indexed
     with that integer.

   The following functions are meant to be used when a unit is about
   to be deindexed and removed from the game, via RemoveUnit() or when
   it dies.
   
   - AddUnitEndEventCondition: Adds a contitional boolexpr variable
   - AddUnitEndEventAction:    Adds an action code
   - GetDeindexedIndex:        Returns the index of the removed unit
   - GetDeindexedUnit:         Returns the unit about to remove
 
  ADVANTAGES:
   - Very easy to use
   - Inline friendly
   - It uses arrays instead of Hashtables
   - You can set the max amount of units in your map.

  DISADVANTAGE:
   - Uses Unit's user data, so if in your map you use this feature in
     your units, this system will put issues.
     
  CONFIGURATION: "SIZE" Constant.
  Here you can define the maximum amount of units that your game will manage.
  If you REAAALLLY need that, please set the SIZE variable with the required
  amount, else DO NOT MODIFY ANYTHING.
 
  CREDITS:
   - Magtheridon96 & Troll-Brain for his nice support and help me notice some
     flaws in the code.
*/
globals
    private constant integer SIZE = 8190 // Here you set the array size, just if you need it, ok??
    private          integer I    = 0    // Stores the deallocated unit index...
    private          unit    U    = null // Stores the deallocated unit...
    private          trigger T    = null // a trigger which will be fired when a unit is deallocated.
endglobals

private struct data extends array [SIZE]
    unit u
   
    implement Alloc
   
    method destroy takes nothing returns nothing
        set I = this
        set U = .u
        if T != null then
            if TriggerEvaluate(T) then
                call TriggerExecute(T)
            endif
        endif
        call SetUnitUserData(.u, 0)
        set .u = null
        call .deallocate()
    endmethod
   
    static method create takes unit u returns thistype
        local thistype this
        if GetUnitUserData(u) < 1 then
            set this = thistype.allocate()
            call SetUnitUserData(u, integer(this))
        else
            set this = thistype(GetUnitUserData(u))
        endif
        set this.u = u
        return this
    endmethod
endstruct

// public functions
function GetUnitIndex takes unit u returns integer
    return GetUnitUserData(u)
endfunction

function GetIndexUnit takes integer index returns unit
    return data(index).u
endfunction

function GetDeindexedIndex takes nothing returns integer
    return I
endfunction

function GetDeindexedUnit takes nothing returns unit
    return U
endfunction

function AddUnitEndEventCondition takes boolexpr b returns triggercondition
    if T == null then
        set T = CreateTrigger()
    endif
    return TriggerAddCondition(T, b)
endfunction

function AddUnitEndEventAction takes code c returns triggeraction
    if T == null then
        set T = CreateTrigger()
    endif
    return TriggerAddAction(T, c)
endfunction
// end public functions

private function ClearUnit takes unit u returns nothing
    call data(GetUnitIndex(u)).destroy()
endfunction

hook RemoveUnit ClearUnit

private function indexit takes nothing returns boolean
    return data.create(GetTriggerUnit()) < 0 // just to make it boolean :)
endfunction

private function indexit2 takes nothing returns boolean
    return data.create(GetFilterUnit()) < 0 // just to make it boolean :)
endfunction

private function dead takes nothing returns boolean
    if not IsUnitType(GetTriggerUnit(), UNIT_TYPE_HERO) then
        call ClearUnit(GetTriggerUnit())
    endif
    return false
endfunction

private function init takes nothing returns nothing
    local trigger t = CreateTrigger()
    local rect r = GetWorldBounds()
    call TriggerRegisterEnterRectSimple(t, r)
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SUMMON)
    call TriggerAddCondition(t, Condition(function indexit))
    call GroupEnumUnitsInRect(bj_lastCreatedGroup, r, Condition(function indexit2))
    set t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_DEATH)
    call TriggerAddCondition(t, Condition(function dead))
    set t = null
    set r = null
endfunction

endlibrary


Changelog:

  • 1.0: Initial release.
  • 1.1: Added detection of units removed via [lcode=jass]RemoveUnit()[/lcode]
  • 1.2: Added detection of resurrected units.
  • 1.3: Added functionality to trigger a condition or a function when a unit is about to be removed from the game, via [lcode=jass]RemoveUnit()[/lcode] or when it dies. This can be useful when you need to do something with the unit about to be removed like clearing any data attachment done to it. I don't plan to add more features, only optimization unless a good reason makes merits to an addition.

Feel free to comment.
13 years
obviously indexing is bugged and deindexing just plain doesn't work

you're better off just having IndexUnit and DeindexUnit functions
13 years
Quote from: nestharus on December 12, 2012, 02:24:20 AM
obviously indexing is bugged and deindexing just plain doesn't work
I've checked and rechecked the code and I don't see where it bugs or fails. Is a scenario issue??

Quoteyou're better off just having IndexUnit and DeindexUnit functions
Well, the idea is that user don't worry about removing index, it should only worried to get the index or unit and use it.
13 years
What about calling RemoveUnit? :o
Your system would ignore units removed using RemoveUnit :/
13 years
edited 13 years
http://www.hiveworkshop.com/forums/2254876-post17.html

Also hook are quite useless in the current state :

- you can't use the function arguments of the hooked function, nor the returned value ...
- if you want to use the hooked function inside the hook (and it's the case there) you have to do some silly stuff to avoid infinite recursivity.

The only way where hooks are "useful" is for debug stuff.
13 years
Quote from: Troll-Brain on December 14, 2012, 12:29:21 PM
http://www.hiveworkshop.com/forums/2254876-post17.html

Also hook are quite useless in the current state :

- you can't use the function arguments of the hooked function, nor the returned value ...
- if you want to use the hooked function inside the hook (and it's the case there) you have to do some silly stuff to avoid infinite recursivity.

The only way where hooks are "useful" is for debug stuff.
Well, I was able to use hooks in the new version and it works like a charm. Please check first post and the test map.
13 years
edited 13 years
Frankly i don't really remember how hooks are "compiled", so i could be wrong before.
Anyway, that doesn't change my point of view about this resource (stated on hiveworkshop)

Also what about units which are resurrected with an active spell such as the Paladin's one ?
13 years
Quote from: Troll-Brain on January 05, 2013, 07:23:53 AM
Frankly i don't really remember how hooks are "compiled", so i could be wrong before.
Anyway, that doesn't change my point of view about this resource (stated on hiveworkshop)

Also what about units which are resurrected with an active spell such as the Paladin's one ?
Checked and updated. Thanks for your revision ;)
13 years
edited 13 years
Interesting, so such units trigger the summont event and it's equal to GetTriggerUnit ?
Also you should null the "u" member on deallocate.

DId i've already said that i think this library is pointless ? :p

EDIT : And meh you're doing it wrong, i would expect that an unit keep the same data until it is removed of the game, even if it dies, and then revives.
Actually it's not always the case. And the best way is to use the 'Adef' bug, so end of this resource ?
13 years
Quote from: Troll-Brain on January 07, 2013, 03:28:41 PM
Interesting, so such units trigger the summont event and it's equal to GetTriggerUnit ?
Also you should null the "u" member on deallocate.
Ok, added to 1.3...

QuoteDId i've already said that i think this library is pointless ? :p
In some way yes, but there's still some people who still loves to use this as attachment system... so I want to offer a simple version of this kind of tool.

QuoteEDIT : And meh you're doing it wrong, i would expect that an unit keep the same data until it is removed of the game, even if it dies, and then revives.
Actually it's not always the case. And the best way is to use the 'Adef' bug, so end of this resource ?
Well, I thought this but at the end we have this idea: if a unit dies, the script removes the use of attach something and anything attached to it should be removed. If you (for ANY chance) can revive it, then the script will reassign an index to use it.

Actually I'm going to make available this feature and I don't expect to add more features.
13 years
I'm not sure i understand what you meant, so i will wait for your update, but for now it sounds wrong on my ears.
13 years
I simply didn't understand what was your plan for the update.
Now as i expected it fails, because when an unit dead it lost its index and that's 100 % wrong, not only because it can be resurrected but because then you can't use corpses ...
Something like the demo spell i've made with my UnitLL resource will not work with your indexer behavior.

There is only 2 way for unit indexing : recycle periodically the ids (of removed units), or deindex it on remove "event", and this last one is much better because it gives you more possibilities and controls.
13 years
As Troll-Brain said, this needs to retain unit data while they're "out of scope".
The only cool way is by taking advantage of the Defend bug (Credits to all the Wc3c people involved in discovering it (I think PurplePoot or Anitarf mostly?))