• 🏆 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] IndexerUtils

Level 11
Joined
Sep 30, 2009
Messages
697
A little systems made by me hope you find it useful. Description inside the code.

Requires:

JASS:
//############################## ~IndexerUtils ##################################//
//##
//## Version:       1.0
//## System:        Axarion
//## AutoIndex:     grim001
//## AIDS:          Jesus4Lyf
//## UnitIndexer:   Nestharus
//##
//############################### DESCRIPTION ###################################//
//##
//## This system combines the Enter- and Leave-Events of AutoIndex, AIDS and 
//## UnitIndexer. I made this to save some time when doing systems which should
//## be compatible with all indexers.
//## 
//############################### HOW DOES IT WORK ##############################//
//## 
//## To use this system create a struct and implement the IndexerUtils module.   
//## 
//################################# METHODS #####################################//
//##   
//##    You can implement these functions into your struct. They are 
//##    all optional. 
//##
//##    - happens when a unit enters which has the ability.
//##        static method onIndex takes unit u returns nothing
//## 
//##    - happens when a unit leaves the map with the ability    
//##        static method onDeindex takes unit u returns nothing
//##
//##    - defines for which units the event should be fired:
//##        static method onFilter takes unit u returns boolean
//##
//################################################################################//

library IndexerUtils requires optional UnitIndexer, optional AutoIndex, optional AIDS //one is required!

module IndexerUtils 
    
    //for AIDS
    static if LIBRARY_AIDS then
    
        static if thistype.onUnitDeindex.exists then
            private static method onUnitDeindexed takes nothing returns boolean
                static if thistype.onFilter.exists then
                    if thistype.onFilter(u) then
                        call thistype.onUnitDeindex(GetIndexUnit(AIDS_GetDecayingIndex()))
                    endif
                else
                    call thistype.onUnitDeindex(GetIndexUnit(AIDS_GetDecayingIndex()))
                endif
                return false
            endmethod
        endif
        
        static if thistype.onUnitIndex.exists then
            private static method onUnitIndexed takes nothing returns boolean
                static if thistype.onFilter.exists then
                    if thistype.onFilter(u) then
                        call thistype.onUnitIndex(AIDS_GetEnteringIndexUnit())
                    endif
                else
                    call thistype.onUnitIndex(AIDS_GetEnteringIndexUnit())
                endif
                return false
            endmethod
        endif
        
        static if thistype.onUnitIndex.exists then
            static if thistype.onUnitDeindex.exists then
                private static method onInit takes nothing returns nothing
                    call AIDS_RegisterOnDeallocate(Condition(function thistype.onUnitDeindexed))
                    call AIDS_RegisterOnEnter (Condition(function thistype.onUnitIndexed))
                endmethod
            else
                private static method onInit takes nothing returns nothing
                    call AIDS_RegisterOnEnter (Condition(function thistype.onUnitIndexed))
                endmethod
            endif
        elseif thistype.onUnitDeindex.exists then
            private static method onInit takes nothing returns nothing
                call AIDS_RegisterOnDeallocate(Condition(function thistype.onUnitDeindexed))
            endmethod
        endif
    
    //for AutoIndex
    elseif LIBRARY_AutoIndex then
        
        static if thistype.onUnitDeindex.exists then
            private static method onUnitDeindexed takes unit u returns nothing
                static if thistype.onFilter.exists then
                    if thistype.onFilter(u) then
                        call thistype.onUnitDeindex(u)
                    endif
                else
                    call thistype.onUnitDeindex(u)
                endif
            endmethod
        endif
        
        static if thistype.onUnitIndex.exists then
            private static method onUnitIndexed takes unit u returns nothing
                static if thistype.onFilter.exists then
                    if thistype.onFilter(u) then
                        call thistype.onUnitIndex(u)
                    endif
                else
                    call thistype.onUnitIndex(u)
                endif
            endmethod
        endif
        
        static if thistype.onUnitIndex.exists then
            static if thistype.onUnitDeindex.exists then
                private static method onInit takes nothing returns nothing
                    call OnUnitDeindexed(thistype.onUnitDeindexed)
                    call OnUnitIndexed(thistype.onUnitIndexed)
                endmethod
            else
                private static method onInit takes nothing returns nothing
                    call OnUnitIndexed(thistype.onUnitIndexed)
                endmethod
            endif
        elseif thistype.onUnitDeindex.exists then
            private static method onInit takes nothing returns nothing
                call OnUnitDeindex  (Condition(function thistype.onUnitIndexed))
            endmethod
        endif

    // for UnitIndexer
    elseif LIBRARY_UnitIndexer then
        
        static if thistype.onUnitDeindex.exists then
            private static method onUnitDeindexed takes nothing returns boolean
                static if thistype.onFilter.exists then
                    if thistype.onFilter(u) then
                        call thistype.onUnitDeindex(GetIndexedUnit())
                    endif
                else
                    call thistype.onUnitDeindex(GetIndexedUnit())
                endif
                return false
            endmethod
        endif
        
        static if thistype.onUnitIndex.exists then
            private static method onUnitIndexed takes nothing returns boolean
                static if thistype.onFilter.exists then
                    if thistype.onFilter(u) then
                        call thistype.onUnitIndex(GetIndexedUnit())
                    endif
                else
                    call thistype.onUnitIndex(GetIndexedUnit())
                endif
                return false
            endmethod
        endif
        
        static if thistype.onUnitIndex.exists then
            static if thistype.onUnitDeindex.exists then
                private static method onInit takes nothing returns nothing
                    call OnUnitDeindex(Condition(function thistype.onUnitDeindexed))
                    call OnUnitIndex  (Condition(function thistype.onUnitIndexed))
                endmethod
            else
                private static method onInit takes nothing returns nothing
                    call OnUnitIndex  (Condition(function thistype.onUnitIndexed))
                endmethod
            endif
        elseif thistype.onUnitDeindex.exists then
            private static method onInit takes nothing returns nothing
                call OnUnitDeindex  (Condition(function thistype.onUnitIndexed))
            endmethod
        endif
    endif
endmodule

endlibrary
 
Last edited:
Level 31
Joined
Jul 10, 2007
Messages
6,306
The struct was made as a delegate struct if a user wants to implement only one of the two functions. I made it in one submission because i wanted to. If everyone wants me to make two i will do so.

Then use statics ifs around those methods in the struct? If I were to use this, I'd rather not have extra vars/methods in my struct. Minimize it = ).

Also keep in mind that this doesn't solve the problem of systems using a specific indexing system. Sure, it would be nice if everyone just went through this, but then again, the systems have features that are entirely incompatible, like the locks on AIDS.

People will use what people will use based on the features. All 3 indexing systems take very different approaches. This utility just follows the UnitIndexer minimalist approach >.>.

If someone was to use UnitIndexer, they might use this. If they were to use AutoIndex or AIDS, they probably wouldn't use this.

I hope you get what I'm saying = ). If a system like this is only practical on one of the things it is meant to support, why would someone use it then? If you added static ifs perhaps in support of all 3 systems (making extra features do something or nothing), then people would possibly use this.

However, by doing this, we run into compatibility issues. For example, if someone was to try and retrieve a unit going out of scope (UnitIndexer/AutoIndex), they would fail on AIDS.

Do you see my point?

I suppose this would be useful for systems designed for this API though.

Your static ifs are sloppy in the module (extra triggers/methods even when the methods that would be using them are not present). Also, in the case of structs, you need a filter and you need to see if a struct is allocated, which is why the indexing systems have modules and functions.

This still needs some work ^>^. I suggest you take a look through the UnitIndexer module code as that has all of the necessary static ifs you will need.

Furthermore, your method names are ambiguous. onIndex doesn't tell me much...
 
Last edited:
Level 31
Joined
Jul 10, 2007
Messages
6,306
JASS:
private static method onInit takes nothing returns nothing
            static if thistype.onUnitDeindex.exists then
                call OnUnitDeindex(Condition(function thistype.onUnitDeindexed))
            endif
            static if thistype.onUnitIndex.exists then
                call OnUnitIndex  (Condition(function thistype.onUnitIndexed))
            endif
        endmethod

Even if or doesn't exist, you can nest it..

JASS:
    static if thistype.unitIndex.exists then
        static if thistype.unitDeindex.exists then
            private static method onInit takes nothing returns nothing
                call OnUnitIndex(Condition(function thistype.onIndexEvent))
                call OnUnitDeindex(Condition(function thistype.onDeindexEvent))
            endmethod
        else
            private static method onInit takes nothing returns nothing
                call OnUnitIndex(Condition(function thistype.onIndexEvent))
            endmethod
        endif
    elseif thistype.unitDeindex.exists then
        private static method onInit takes nothing returns nothing
            call OnUnitDeindex(Condition(function thistype.onDeindexEvent))
        endmethod
    endif
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
look through the top ; |, then unitIndex, then unitDeindex. Normally, filters would just be fine and good. However, some libraries might be working alongside with a unit indexer, so they might want to see if their own struct is allocated or not : P. It is in these scenarios (like in UnitEvent) that the unitIndexAllocated comes in handy = ).

Now at this point, it is a little insane. Your code is probably fine with just the filter. However, if you want to squeeze every last little bit of performance out, use this format.
JASS:
module UnitIndexStruct
    static if thistype.unitFilter.exists then
        static if thistype.unitIndex.exists then
            private static boolean array allocated
            
            public method operator unitIndexAllocated takes nothing returns boolean
                return allocated[this]
            endmethod
        else
            public method operator unitIndexAllocated takes nothing returns boolean
                return unitFilter(GetUnitById(this))
            endmethod
        endif
    else
        public static constant boolean unitIndexAllocated = true
    endif
    
    static if thistype.unitIndex.exists then
        private static method onIndexEvent takes nothing returns boolean
            static if thistype.unitFilter.exists then
                if (unitFilter(GetIndexedUnit())) then
                    set allocated[GetIndexedUnitId()] = true
                    call thistype(GetIndexedUnitId()).unitIndex()
                endif
            else
                call thistype(GetIndexedUnitId()).unitIndex()
            endif
            return false
        endmethod
        
        static if thistype.unitDeindex.exists then
            public method operator unit takes nothing returns unit
                return indexedUnit[this]
            endmethod
        else
            public method operator unit takes nothing returns unit
                return indexedUnit(this)
            endmethod
        endif
    endif
    
    static if thistype.unitDeindex.exists then
        private static method onDeindexEvent takes nothing returns boolean
            static if thistype.unitFilter.exists then
                static if thistype.unitIndex.exists then
                    if (allocated[GetIndexedUnitId()]) then
                        set allocated[GetIndexedUnitId()] = false
                        call thistype(GetIndexedUnitId()).unitDeindex()
                    endif
                else
                    if (unitFilter(GetIndexedUnit())) then
                        call thistype(GetIndexedUnitId()).unitDeindex()
                    endif
                endif
            else
                call thistype(GetIndexedUnitId()).unitDeindex()
            endif
            return false
        endmethod
    endif
    
    static if thistype.unitIndex.exists then
        static if thistype.unitDeindex.exists then
            private static method onInit takes nothing returns nothing
                call OnUnitIndex(Condition(function thistype.onIndexEvent))
                call OnUnitDeindex(Condition(function thistype.onDeindexEvent))
            endmethod
        else
            private static method onInit takes nothing returns nothing
                call OnUnitIndex(Condition(function thistype.onIndexEvent))
            endmethod
        endif
    elseif thistype.unitDeindex.exists then
        private static method onInit takes nothing returns nothing
            call OnUnitDeindex(Condition(function thistype.onDeindexEvent))
        endmethod
    endif
endmodule
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
I think so too.

at least do this
JASS:
static if thistype.unitFilter.exists then
//code
else
    public static method unitFilter takes unit u returns boolean
        return GetUnitUserData(u) != 0
    endif
endif

If you wanted to check if a unit was allocated for the struct >.>... if unitFilter only exists some of the time, you can't use that as a check outside of the module to see if the struct was allocated or not can you? This means that you need to generate your own unitFilter that just sees if the unit was indexed at all (global indexing filters won't index units if they return false, so you just need to compare to 0).

These extra method and native calls are slower than going through the boolean array... at this point you might just use unitIndexAllocated idea ; P.

edit
I guess it's your intention to make it impossible to determine whether a struct is allocated or not, so things that work with a struct (not from inside) will be impossible to do. W/e, I tried to reason with you, but oh well.
 
Last edited:

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,464
It would be better to just get everyone to agree on a single unit indexer system.

I don't think you should limit each of the three indexing libraries to just a filter, an allocator and a deallocator, because you are taking away from the unique qualities of each. AIDS, AutoIndex and UnitIndexer have their pros and cons.

Let me look into this further and try to come up with a solution for you that does what you want yet doesn't look like a confounded mess, as you've noticed this system has become.
 
Last edited:

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,464
This also fixes some syntax errors you missed. The onUnitIndex/onUnitDeindex methods now take a second argument - the index of the unit being evaluated. It does almost no good at all to have a unit without its index.

JASS:
//############################## ~IndexerUtils ##################################//
//##
//## Version:       2.0
//## System:        Axarion
//## UnitIndexer:   Nestharus   http://www.hiveworkshop.com/forums/showthread.php?t=172090
//## AIDS:          Jesus4Lyf   http://www.thehelper.net/forums/showthread.php?t=130752
//## AutoIndex:     grim001     http://www.wc3c.net/showthread.php?t=105643
//##
//############################### DESCRIPTION ###################################//
//##
//## This system combines the allocate and deallocate events of AutoIndex, AIDS
//## and UnitIndexer. This is to save time and mistakes when making systems which
//## are compatible with all unit indexers.
//##
//############################### HOW IT WORKS ##################################//
//##
//## To use this system, implement the IndexerUtils module into any struct.
//##
//################################# METHODS #####################################//
//##
//##    You can implement any of these optional methods into your struct.
//##
//##    static method onUnitFilter takes unit u returns boolean
//##        - validates units as they are indexed/deindexed.
//##
//##    static method onIndex takes unit u, integer index returns nothing
//##        - called when a valid unit enters the map.
//##
//##    static method onDeindex takes unit u, integer index returns nothing
//##        - called when a valid unit leaves the map.
//##
//################################################################################//

library IndexerUtils requires optional UnitIndexer, optional AutoIndex, optional AIDS //one is required!

module IndexerUtils 
    
    //! textmacro IndexerUtils__General takes FUNC, GET, INDEX
        static if thistype.$FUNC$.exists then
            private static method $FUNC$ed takes nothing returns boolean
                static if thistype.onUnitFilter.exists then
                    if not thistype.onUnitFilter($GET$) then
                        return false
                    endif
                endif
                call thistype.$FUNC$($GET$, $INDEX$)
                return false
            endmethod
        endif
    //! endtextmacro
    
    static if LIBRARY_UnitIndexer then
        
        //! runtextmacro IndexerUtils__General("onUnitIndex", "GetIndexedUnit()", "GetIndexedUnitId()")
        //! runtextmacro IndexerUtils__General("onUnitDeindex", "GetIndexedUnit()", "GetIndexedUnitId()")
        
    elseif LIBRARY_AIDS then
        
        //! runtextmacro IndexerUtils__General("onUnitIndex", "AIDS_GetEnteringIndexUnit()", "AIDS_GetIndexOfEnteringUnit()")
        //! runtextmacro IndexerUtils__General("onUnitDeindex", "GetIndexUnit(AIDS_GetDecayingIndex())", "AIDS_GetDecayingIndex()")
        
    elseif LIBRARY_AutoIndex then
        
        //! textmacro IndexerUtils__AutoIndex takes FUNC
            static if thistype.$FUNC$.exists then
                private static method $FUNC$ed takes unit u returns nothing
                    static if thistype.onUnitFilter.exists then
                        if not thistype.onUnitFilter(u) then
                            return
                        endif
                    endif
                    call thistype.$FUNC$(u, GetUnitId(u))
                endmethod
            endif
        //! endtextmacro
        //! runtextmacro IndexerUtils__AutoIndex("onUnitIndex")
        //! runtextmacro IndexerUtils__AutoIndex("onUnitDeindex")
        
    endif
    
    //! textmacro IndexerUtils__Init takes SETUP, FUNC, INPUT
        static if thistype.$FUNC$.exists then
            call $SETUP$($INPUT$)
        endif
    //! endtextmacro
    
    private static method onInit takes nothing returns nothing
        static if LIBRARY_UnitIndexer then
            //! runtextmacro IndexerUtils__Init("OnUnitIndex", "onUnitIndex", "Condition(function thistype.onUnitIndexed)")
            //! runtextmacro IndexerUtils__Init("OnUnitDeindex", "onUnitDeindex", "Condition(function thistype.onUnitDeindexed)")
        elseif LIBRARY_AIDS then
            //! runtextmacro IndexerUtils__Init("AIDS_RegisterOnEnter", "onUnitIndex", "Condition(function thistype.onUnitIndexed)")
            //! runtextmacro IndexerUtils__Init("AIDS_RegisterOnDeallocate", "onUnitDeindex", "Condition(function thistype.onUnitDeindexed)")
        elseif LIBRARY_AutoIndex then
            //! runtextmacro IndexerUtils__Init("OnUnitIndexed", "onUnitIndex", "thistype.onUnitIndexed")
            //! runtextmacro IndexerUtils__Init("OnUnitDeindexed", "onUnitDeindex", "thistype.onUnitDeindexed")
        endif
    endmethod
    
endmodule

endlibrary
 
Last edited:
Level 31
Joined
Jul 10, 2007
Messages
6,306
I still think, that in the case of structs, it is important to be able to see if an index is allocated or not (keep in mind that I think using an array would be better than the below operators)

JASS:
static if thistype.unitFilter.exists
    public method operator unitIndexAllocated takes nothing returns boolean
        return GetUnitById(this) != null and unitFilter(GetUnitById(this))
    endmethod
else
    public method operator unitIndexAllocated takes nothing returns boolean
        return GetUnitById(this) != null
    endmethod
endif

Also, bribe, onFilter should be onUnitFilter : P.


Then you need function as well : |. The module for structs has a little extra overhead because of the instances. The simple function calls would just be indexing/deindexing.


Also, keep in mind that AIDS is largely incompatible with AutoIndex and UnitIndexer unless you make it so you can't retrieve a unit on deindex : |... retrieving units on deindex is personally very important to me, so I would never use this : P
 
Level 8
Joined
Oct 3, 2008
Messages
367
I like the concept of this, I'll give it that. Some sort of unification in the way of unit indexing is good, but there's always trouble because each system in the Unit Indexing Trinity has some sort of unique features not possible anywhere else or something.

It's great if the only thing people used in unit indexers was the indexing itself, but unfortunately they don't. Because of this, I don't know what to do with this. I guess I'll have to rely on how users feel about it.
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
Well Azlier, you're thinking about it wrong : ).

If people make systems of of this API, then they automatically support all 3 indexing systems, no matter what is in the map. The drawback is that they have to limit themselves to what they use.

The map maker's only extra work is having to past this into their map on top of whatever indexing system they are using.

The idea is actually ok if you're system only needs basic indexing/deindexing capabilities.

My argument is with some of the missing stuff for the module = P. I'm also pushing for functions.

I hope this gives you a clearer picture of what's going on here azlier : ).
 
Level 8
Joined
Oct 3, 2008
Messages
367
Well if those people don't need the extra features then it works fine. But if they do, this can't be used as a specific system is needed. All it does is serve as a way to have less requirements and less if statements if you deign to make your script capable of using all three systems.
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
All it does is serve as a way to have less requirements and less if statements if you deign to make your script capable of using all three systems.

That was the purpose of this script in the first place >.< This means that the script's uselessness can no longer be debated. If a system doesn't need the extra features, then this script is very useful : P.


The only problems I had with this script was the module.
I still think, that in the case of structs, it is important to be able to see if an index is allocated or not (keep in mind that I think using an array would be better than the below operators)

And lack of indexing functions like OnUnitIndex and OnUnitDeindex.


Also let it be noted that I'm still a major advocate for UnitIndexer ; o.

And let it be noted that this post marks my 600th post (eww.. apparently some of my posts just went away... this was 600th when I posted it).
 
Last edited:
Top