System Unit Indexer

Status
Not open for further replies.

Nestharus

o-o
Reaction score
84
Unit Indexer
v2.2.1.1
By Nestharus

Introduction
Unit Indexer is a system for indexing units.

  • It has a very efficient deindexing function (only this lib has it) and an efficient indexing function.
  • It has locks.
  • Global filter for indexing.
  • Includes functions for enabling/disabling the unit indexer.
  • Unit validation (sees if a unit is indexed).
  • Will eventually have an API for PUI.
  • Grants access to units before they go out of scope.
  • Has by far the best indexing struct module of every indexing system.

System Code
JASS:
library UnitIndexer initializer init
//Primary index filter
private function IndexFilter takes unit u returns boolean
    return true
endfunction
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//~~ Unit Indexer ~~ By Nestharus ~~ Version 2.2.1.1 ~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//Description:
//      Unit Indexer is a system for indexing units with Unit User Data. It is made
//      to have minimal features while retaining safety.
//
//      Basic features include an indexing filter, indexer enable/disable, and global indexer events
//
//      To apply more filters and minimize evaluation calls (like unit type index event filter),
//      just create your own filter and run through that.
//
//      ex-
//          local Trigger unitTypeEvent = CreateTrigger()
//          if (GetUnitTypeId(GetIndexedUnit()) == 'hpea') then
//              call TriggerEvaluate(unitTypeEvent)
//
//Installation:
//      When running for the first time, hit save and restart WE, then comment out the line below.
//!         external ObjectMerger w3a Adef OUIN anam "Unit Indexing" ansf "(Unit Indexing)" aart "" arac 0
//
//API:
//////////////////////////////////////////////////////////////
//      -function EnableUnitIndexing takes boolean val returns nothing
//              Disables/Enables the unit indexer
//
//      -function IsUnitIndexingEnabled takes nothing returns boolean
//              Returns a boolean that determines if the unit 
//              indexer is enabled
//
//      -function IndexUnit takes unit u returns integer
//          Indexes unit u if the unit is not already indexed and
//          returns its index.
//
//      -function GetUnitById takes integer index returns unit
//              Returns a unit given an index
//
//      -function GetUnitId takes unit u returns integer
//              Gets a unit's index
//
//      -function IsUnitIndexed takes unit u returns boolean
//              Returns a boolean that determines if the unit
//              is indexed
//
//      -function LockUnitIndex takes integer index returns nothing
//              Applies a lock on the unit index (can be layered)
//              Locks make it so that the given index is not recycled.
//
//      -function UnlockUnitIndex takes integer index returns nothing
//              Unlocks a unit index. To get the index to recycle, each
//              lock must be unlocked.
//
//Events:
//////////////////////////////////////////////////////////////
//  Each event is a struct that extends array. 
//
//  -API
//      -static method add takes boolexpr c returns nothing
//          Adds code to be run at event.
//
//  -Structs
//      -UnitIndexEvent
//          Fires when a unit is indexed
//
//          -function GetIndexedUnit takes nothing returns unit
//              Returns the indexed unit.
//
//          -function GetIndexedUnitId takes nothing returns integer
//              Returns the index.
//
//      -UnitDeindexEvent
//          Fires when a unit is deindexed
//
//          -function GetIndexedUnit takes nothing returns unit
//              Returns the deindexed unit.
//
//          -function GetIndexedUnitId takes nothing returns integer
//              Returns the index.
//
//Unit Index Struct Module:
//////////////////////////////////////////////////////////////
//  A module that will automatically call indexing/deindexing methods for you as well
//  as automatically check against your own filter. It runs completely off of static ifs,
//  so there are minimal calls and there is minimal code.
//
//  module UnitIndexStruct
//      readonly unit unit
//          The indexed unit of the struct
//
//      indexAllocated
//          Use this to determine whether an index is allocated or not. Useful
//          if you only want to run event code for a struct if that struct is
//          allocated.
//
//          ex- if (indexedAllocated) then
//                  //run code
//              endif
//
//
//      Interface:
//          private method unitIndex takes nothing returns nothing
//              This method is called when a unit is indexed. Not having
//              this method in your struct will just remove the indexing event
//              code within the module.
//
//              If there is a filter, this will only run if the filter returns true.
//
//          private method unitDeindex takes nothing returns nothing
//              This method is called when a unit is deindexed. Not having
//              this method in your struct will just remove the deindexing event
//              code within the module.
//
//              If there is a filter and a unitIndex, this will only run if the struct is allocated.
//              If there is no unitIndex method, this will run if the filter returns true.
//
//          private static method unitIndexFilter takes unit u returns boolean
//              This method is called when attempting to index a unit. Not having
//              this method in your struct will just remove the filter check.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    globals
        private boolean indexerEnabled = true
        private trigger enter = CreateTrigger()
        private trigger undefend = CreateTrigger()
        
        private trigger onIndex = CreateTrigger()
        private trigger onDeindex = CreateTrigger()
        
        private unit array indexedUnit
        private integer array lock
        
        private integer instanceCount = 0
        private integer array recycle
        private integer recycleCount = 0
        
        private integer array indexedArray
        private integer indexed = 0
        
        private unit replacedUnit = null
    endglobals
    
    function EnableUnitIndexing takes boolean val returns nothing
        set indexerEnabled = val
    endfunction
    
    function IsUnitIndexingEnabled takes nothing returns boolean
        return indexerEnabled
    endfunction
    
    function GetUnitById takes integer index returns unit
        return indexedUnit[index]
    endfunction
    
    function GetUnitId takes unit u returns integer
        return GetUnitUserData(u)
    endfunction
    
    function IsUnitIndexed takes unit u returns boolean
        return (indexedUnit[GetUnitUserData(u)] == u)
    endfunction
    
    function LockUnitIndex takes integer index returns nothing
        set lock[index] = lock[index] + 1
    endfunction
    
    function GetReplacedUnit takes nothing returns unit
        return replacedUnit
    endfunction
    
    struct UnitIndexEvent extends array
        public static method add takes boolexpr c returns nothing
            call TriggerAddCondition(onIndex, c)
        endmethod
    endstruct
    struct UnitDeindexEvent extends array
        public static method add takes boolexpr c returns nothing
            call TriggerAddCondition(onDeindex, c)
        endmethod
    endstruct
    
    function IndexUnit takes unit u returns integer
        set indexed = indexed + 1
        set indexedArray[indexed] = GetUnitUserData(u)
        
        if (indexedUnit[indexed] != u) then
            if (recycleCount != 0) then
                set recycleCount = recycleCount - 1
                set indexedArray[indexed] = recycle[recycleCount]
            else
                set instanceCount = instanceCount + 1
                set indexedArray[indexed] = instanceCount
            endif
            
            //set fields, add ability, set index data
            set indexedUnit[indexedArray[indexed]] = u
            call UnitAddAbility(u, 'OUIN')
            call SetUnitUserData(u, indexedArray[indexed])
            
            call TriggerEvaluate(onIndex)
        endif
        
        set indexed = indexed - 1
        return indexedArray[indexed+1]
    endfunction
    
    function UnlockUnitIndex takes integer index returns nothing
        if (lock[index] > 0) then
            set lock[index] = lock[index] - 1
            if (lock[index] == 0 and indexedUnit[index] == null) then
                set recycle[recycleCount] = index
                set recycleCount = recycleCount + 1
            endif
        endif
    endfunction
    
    function GetIndexedUnit takes nothing returns unit
        return indexedUnit[indexedArray[indexed]]
    endfunction
    
    function GetIndexedUnitId takes nothing returns integer
        return indexedArray[indexed]
    endfunction
    
    private function onEnter takes nothing returns boolean
        //retrieve unit and unit type id
        local unit filterUnit
        if (indexerEnabled) then
            set filterUnit = GetFilterUnit()
            //make sure not allocated and enabled
            if (indexedUnit[GetUnitUserData(filterUnit)] != filterUnit and IndexFilter(filterUnit)) then
                //allocate
                set indexed = indexed + 1
                if (recycleCount != 0) then
                    set recycleCount = recycleCount - 1
                    set indexedArray[indexed] = recycle[recycleCount]
                else
                    set instanceCount = instanceCount + 1
                    set indexedArray[indexed] = instanceCount
                endif
                
                //set fields, add ability, set index data
                set indexedUnit[indexedArray[indexed]] = filterUnit
                call UnitAddAbility(filterUnit, 'OUIN')
                call SetUnitUserData(filterUnit, indexedArray[indexed])
                
                call TriggerEvaluate(onIndex)
                
                set indexed = indexed - 1
            endif
            set filterUnit = null
        endif
        
        return false
    endfunction
    
    private function onUndefend takes nothing returns boolean
        local unit u = GetFilterUnit()
        if (GetUnitAbilityLevel(u, 'OUIN') == 0) then
            set indexed = indexed + 1
            set indexedArray[indexed] = GetUnitUserData(u)
            
            if (indexedUnit[indexedArray[indexed]] == u) then
                call TriggerEvaluate(onDeindex)
                
                if (lock[indexedArray[indexed]] == 0) then
                    set recycle[recycleCount] = indexedArray[indexed]
                    set recycleCount = recycleCount + 1
                endif
                set indexedUnit[indexedArray[indexed]] = null
            endif
            set indexed = indexed - 1
        endif
        return false
    endfunction
    
    private struct UnitIndexing extends array
        private static method onInit takes nothing returns nothing
            local region world = CreateRegion()
            local integer i = 15
            local boolexpr bc = Condition(function onUndefend)
            local rect r = GetWorldBounds()
            
            call RegionAddRect(world, r)
            call TriggerRegisterEnterRegion(enter, world, Condition(function onEnter))
            
            loop
                call TriggerRegisterPlayerUnitEvent(undefend, Player(i), EVENT_PLAYER_UNIT_ISSUED_ORDER, bc)
                call SetPlayerAbilityAvailable(Player(i), 'OUIN', false)
                exitwhen i == 0
                set i = i - 1
            endloop
            
            call RemoveRect(r)
            set r = null
            set world = null
            set bc = null
        endmethod
    endstruct
    
    private function init takes nothing returns nothing
        local integer i = 15
        local group g = CreateGroup()
        local boolexpr bc = Condition(function onEnter)
        
        loop
            call GroupEnumUnitsOfPlayer(g, Player(i), bc)
            exitwhen i == 0
            set i = i - 1
        endloop
        
        call DestroyGroup(g)
        set g = null
    endfunction
    
    module UnitIndexStruct
        static if thistype.unitIndexFilter.exists then
            static if thistype.unitIndex.exists then
                private static boolean array allocated
                
                public method operator indexAllocated takes nothing returns boolean
                    return allocated[this]
                endmethod
            else
                public method operator indexAllocated takes nothing returns boolean
                    return unitIndexFilter(GetUnitById(this))
                endmethod
            endif
        else
            public static constant method operator indexAllocated takes nothing returns boolean
                return true
            endmethod
        endif
        
        static if thistype.unitIndex.exists then
            private static method onIndexEvent takes nothing returns boolean
                static if thistype.unitIndexFilter.exists then
                    if (unitIndexFilter(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 GetUnitById(this)
                endmethod
            else
                public method operator unit takes nothing returns unit
                    return GetUnitById(this)
                endmethod
            endif
        endif
        
        static if thistype.unitDeindex.exists then
            private static method onDeindexEvent takes nothing returns boolean
                static if thistype.unitIndexFilter.exists then
                    static if thistype.unitDeindex.exists then
                        if (allocated[GetIndexedUnitId()]) then
                            set allocated[GetIndexedUnitId()] = false
                            call thistype(GetIndexedUnitId()).unitDeindex()
                        endif
                    else
                        if (unitIndexFilter(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 UnitIndexEvent.add(Condition(function thistype.onIndexEvent))
                    call UnitDeindexEvent.add(Condition(function thistype.onDeindexEvent))
                endmethod
            else
                private static method onInit takes nothing returns nothing
                    call UnitIndexEvent.add(Condition(function thistype.onIndexEvent))
                endmethod
            endif
        elseif thistype.unitDeindex.exists then
            private static method onInit takes nothing returns nothing
                call UnitDeindexEvent.add(Condition(function thistype.onDeindexEvent))
            endmethod
        endif
    endmodule
endlibrary


Demo
JASS:
struct UnitIndexerDemo extends array
    private method unitIndex takes nothing returns nothing
        call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, GetUnitName(unit) + " was indexed")
    endmethod
    
    private method unitDeindex takes nothing returns nothing
        call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, GetUnitName(unit) + " was deindexed")
    endmethod
    
    private static method unitIndexFilter takes unit u returns boolean
        call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, GetUnitName(u) + " was filtered")
        
        if (GetUnitTypeId(u) == 'hkni') then
            return false
        endif
        return true
    endmethod
    
    implement UnitIndexStruct
endstruct
 

Attachments

  • test map.zip
    15.4 KB · Views: 311
Reaction score
91
Hell no, not another one...
You people should start making indexing systems for personal use, not public.
Btw, the registering interface is bad in my opinion. It would be more user friendly as a simple function call (it should get inlined anyway) instead of the current struct usage.
 

Nestharus

o-o
Reaction score
84
Hell no, not another one...
You people should start making indexing systems for personal use, not public.
Btw, the registering interface is bad in my opinion. It would be more user friendly as a simple function call (it should get inlined anyway) instead of the current struct usage.

The register functions would be huge and fugly, lol : D.

Also the structs help me organize the code (keeps it cleaner). If you didn't notice, there is a load of code o-o.

Oh yea, I did initially make this for private use, but I really liked how it turned out o-o.

You can never have too many indexing systems!!! >: O.

lol
 

Nestharus

o-o
Reaction score
84
I'm telling you the function names would still be long and ugly. Also because this doesn't actually evaluate triggers, you'd use something like add/remove rather than register/unregister. Registering means you pass in a trigger and have it evaluated in the JASS world = P.

JASS:

function AddOnGlobalCreateUnit takes boolexpr c returns triggercondition
function AddOnCreateUnit takes boolexpr c returns triggercondition
function AddOnCreateUnitType takes boolexpr c returns triggercondition
function AddOnGlobalDestroyUnit takes boolexpr c returns triggercondition
function AddOnDestroyUnit takes boolexpr c returns triggercondition
function AddOnDestroyUnitType takes boolexpr c returns triggercondition

function RemoveOnGlobalCreateUnit takes boolexpr c returns triggercondition
function RemoveOnCreateUnit takes boolexpr c returns triggercondition
function RemoveOnCreateUnitType takes boolexpr c returns triggercondition
function RemoveOnGlobalDestroyUnit takes boolexpr c returns triggercondition
function RemoveOnDestroyUnit takes boolexpr c returns triggercondition
function RemoveOnDestroyUnitType takes boolexpr c returns triggercondition
 

Hatebreeder

So many apples
Reaction score
381
I'm telling you the function names would still be long and ugly. Also because this doesn't actually evaluate triggers, you'd use something like add/remove rather than register/unregister. Registering means you pass in a trigger and have it evaluated in the JASS world = P.

JASS:
function AddOnGlobalCreateUnit takes boolexpr c returns triggercondition
function AddOnCreateUnit takes boolexpr c returns triggercondition
function AddOnCreateUnitType takes boolexpr c returns triggercondition
function AddOnGlobalDestroyUnit takes boolexpr c returns triggercondition
function AddOnDestroyUnit takes boolexpr c returns triggercondition
function AddOnDestroyUnitType takes boolexpr c returns triggercondition

function RemoveOnGlobalCreateUnit takes boolexpr c returns triggercondition
function RemoveOnCreateUnit takes boolexpr c returns triggercondition
function RemoveOnCreateUnitType takes boolexpr c returns triggercondition
function RemoveOnGlobalDestroyUnit takes boolexpr c returns triggercondition
function RemoveOnDestroyUnit takes boolexpr c returns triggercondition
function RemoveOnDestroyUnitType takes boolexpr c returns triggercondition

Arn't you doing that right there?
You can add Actions and Conditions to a trigger, but, removing is the problem o_O
I had this kind of a problem before - Once you want to remove actions/conditions, the trigger f*cks up and does weird stuff. Same with destroy trigger.

EDIT: So better create seperate triggers for more controll? Or use wrappers?
 

Nestharus

o-o
Reaction score
84
Er, what I meant by not evaluating triggers is that it doesn't loop through a whole bunch of triggers, it just evaluates once ; ).

I've never had a trigger act weirdly after removing a triggercondition ;o.

Oh yea, and v1.3.1.0 is up. It can now access units right before they go out of scope, fuahaha >: D.

I'll put up a demo of all of the different possible events you can do with this + the event stuff.

For AutoEvent API, it'll be an add on : D.

Also by wrappers, do you mean calling a function rather than UnitGlobalIndex.Create.add() or w/e, because the functions above are the ones I'd use, heh... I thought the OO syntax was nicer, which is why I went with it. The OO syntax also made the code prettier =D.

edit
I just saw what you meant.. no, I just cnp'd those function names for the post because I was lazy and I forgot the parameters/return, haha..

Obviously this is all wrong
JASS:
function RemoveOnGlobalCreateUnit takes boolexpr c returns triggercondition
function RemoveOnCreateUnit takes boolexpr c returns triggercondition
function RemoveOnCreateUnitType takes boolexpr c returns triggercondition
function RemoveOnGlobalDestroyUnit takes boolexpr c returns triggercondition
function RemoveOnDestroyUnit takes boolexpr c returns triggercondition
function RemoveOnDestroyUnitType takes boolexpr c returns triggercondition


should be [ljass]takes triggercondition tc returns nothing[/ljass]

This is the API-
JASS:
//          struct Create extends array
//          struct Destroy extends array
//              static method add takes boolexpr c returns triggercondition
//              static method remove takes triggercondition tc returns nothing
 

Jesus4Lyf

Good Idea™
Reaction score
397
Btw, the registering interface is bad in my opinion. It would be more user friendly as a simple function call (it should get inlined anyway) instead of the current struct usage.
Agreed.
I've never had a trigger act weirdly after removing a triggercondition ;o.
Because, no offense, you're inexperienced. Try stress testing KT2 with a direct trigger condition removal and you will experience a fatal error. You don't want users to experience a fatal error, do you? :)
It's actually a concurrency issue which seems to cause the bug, so far as I can tell.
JASS:
    function GetIndexedUnitId takes nothing returns integer
        return indexed
    endfunction

That cannot and will not ever be approved as meeting the AIDS API ever. You missed concurrency here also. This breaks AIDS structs.
Has complete APIs for AIDS, PUI, and AutoIndex. The addLock and removeLock on the AIDS API don't really do anything in this. If there are enough people wanting it, I can support it.
I can't tell if you're being a smart ass or if you're lying. I don't personally qualify having the same function declarations as meeting the API of a system - I would say it requires the functions to do the same thing, as well. The behavior of your implementation does not match the behavior of the AIDS implementation except for rather specific circumstances.

Lastly, why did you make this? It is better for the community to improve on what already exists rather than write your own for obscure reasons.

I am actually 100% sure you could have written a system which simply requires AIDS. AutoIndex could be written to require AIDS. It is not possible to do the reverse, on the other hand...

I doubt you will ever get a working implementation of SetIndexUnit. The reasons are because data attached to a unit through id may also be attached to its handle (think Damage). If you recreate the data, there is no point in SetIndexUnit. If you do not recreate the data, it is unstable and will break systems which use other indexing APIs such as AIDS. I think that makes most of everything here redundant...?

Carry on... :)
 

Nestharus

o-o
Reaction score
84
Because, no offense, you're inexperienced. Try stress testing KT2 with a direct trigger condition removal and you will experience a fatal error. You don't want users to experience a fatal error, do you?
It's actually a concurrency issue which seems to cause the bug, so far as I can tell.

I wouldn't say I'm at all inexperienced = ), but hmm... actually, because things aren't cleaned up until the end of the cycle, removing a triggercondition from within the trigger itself where that triggercondition wasn't run yet could possibly hurt it. It's all just postulation at this point ; D, but if you say you've run into it, I believe you =).

Actually, when I think about it, my old footmen wars map used to critical error randomly and I could never figure out why... it ran on my UnitDecay library for decaying units, which did a lot of triggercondition removal on the triggers.

I'll test that out =).

That cannot and will not ever be approved as meeting the AIDS API ever. You missed concurrency here also. This breaks AIDS structs.

I guess I should make the AIDS API do what AIDS does like I did with AutoIndex =), just give me a few =o.

I can't tell if you're being a smart ass or if you're lying. I don't personally qualify having the same function declarations as meeting the API of a system - I would say it requires the functions to do the same thing, as well. The behavior of your implementation does not match the behavior of the AIDS implementation except for rather specific circumstances.

Actually, I did it for every system but AIDS, lol... with AIDS I was a little lazy o-o. I'll get on it though, ok = ).

Lastly, why did you make this? It is better for the community to improve on what already exists rather than write your own for obscure reasons.

I honestly really felt like writing a unit indexing system on July 5, lol. When it was done, I thought it turned out pretty darn well, so I submitted it as another alternative.

I am actually 100% sure you could have written a system which simply requires AIDS. AutoIndex could be written to require AIDS. It is not possible to do the reverse, on the other hand...

Well... making AutoIndex use AIDS would be counter intuitive as it works very differently on deindexing. Making this require either of them would be bad too as this works differently from both on deindexing. Also keep in mind that both AutoIndex and Unit Indexer do checking for decay, removal, resurrection, and etc.

I doubt you will ever get a working implementation of SetIndexUnit. The reasons are because data attached to a unit through id may also be attached to its handle (think Damage). If you recreate the data, there is no point in SetIndexUnit. If you do not recreate the data, it is unstable and will break systems which use other indexing APIs such as AIDS. I think that makes most of everything here redundant...?

Hm... well, I think a good way to think of data attached to a handle id is as local to that specific unit. Data attached via the indexed id is local to w/e unit that id references.

So units that are replaced will not get data from the handle id as that data is for the one unit only, even if that unit is to transform or something, but they will get the data off of the indexed id. I guess it's like private and protected : P. That's how I think of it anyways.

The current ReplaceIndexedUnit actually works pretty darn well and runs events for unit type indexing if the types don't match up =), it's just a little hard to use as you have to disable unit indexing if you are creating a new unit to replace the old one and then enable unit indexing.



What I personally want to do is somehow get rid of the 2 hooks this has, but I haven't figured out a way to do it yet =D.

So jesus4lyf, I promise that I will make the AIDS API work as it should, k?

edit
I will be running this code all night to see if the map will crit error

JASS:
struct tester extends array
    private static triggercondition array tc
    private static triggercondition array tc2
    private static integer count = 0
    private static integer count2
    private static trigger t = CreateTrigger()
    private static trigger tr2 = CreateTrigger()
    private static boolean add = true
    private static boolean remove = true
    
    private static boolexpr t0
    private static boolexpr t1
    private static boolexpr t2
    
    private static method test2 takes nothing returns boolean
        if (count > 0) then
            if (count < count2/4) then
                call TriggerRemoveCondition(tr2, tc2[0])
                set count2 = count2 - 1
                set tc2[0] = tc2[count2]
                set tc2[count2] = null
            endif
            
            call TriggerRemoveCondition(t, tc[0])
            set count = count - 1
            set tc[0] = tc[count]
            set tc[count] = null
            
            if (count == 0) then
                set add = true
                set tc[count] = TriggerAddCondition(t, t0)
                set count = count + 1
            endif
        endif
        return false
    endmethod
    
    private static method test1 takes nothing returns boolean
        if (count < 8000 and add) then
            set tc2[count2] = TriggerAddCondition(tr2, t2)
            set count2 = count2 + 1    
        endif
        return false
    endmethod
    
    private static method test takes nothing returns boolean
        if (count < 8000 and add) then
            if (remove) then
                set remove = false
                set tc[count] = TriggerAddCondition(t, t1)
                set count = count + 1
            else
                set remove = true
            endif
            set tc[count] = TriggerAddCondition(t, t0)
            set count = count + 1
        elseif (add) then
            set add = false
        endif
        return false
    endmethod
    
    private static method run takes nothing returns boolean
        call TriggerEvaluate(tr2)
        
        return false
    endmethod
    
    private static method onInit takes nothing returns nothing
        set t0 = Condition(function thistype.test)
        set t1 = Condition(function thistype.test1)
        set t2 = Condition(function thistype.test2)
        
        set tc[count] = TriggerAddCondition(t, t0)
        set count = count + 1
        call TriggerAddCondition(t, Condition(function thistype.run))
        call TriggerRegisterTimerEvent(t, .03125, true)
    endmethod
endstruct


The truth shall soon be known >: O.
 

Jesus4Lyf

Good Idea™
Reaction score
397
Well... making AutoIndex use AIDS would be counter intuitive as it works [DEL]very[/DEL] differently on deindexing.
Think carefully, you'll find it's irrelevant.
Making this require either of them would be bad too as this works differently from both on deindexing.
How?
Also keep in mind that both AutoIndex and Unit Indexer do checking for decay, removal, resurrection, and etc.
AIDS can support that. I dare say it's not even too hard. :)
Think about it, every unit on the map has undefend already and an ID associated, which you know will not be removed before the unit. I intend, ideally, to add an AutoEvents port to AIDS, even, maybe.
Hm... well, I think a good way to think of data attached to a handle id
Woah, wait. You totally didn't "see Damage" like I said. The point is the "takes damage" event is specific to the literal WC3 unit. Which means you're just gonna stuff up systems like that...

So units that are replaced will not get data from the handle id as that data is for the one unit only, even if that unit is to transform or something, but they will get the data off of the indexed id. I guess it's like private and protected : P. That's how I think of it anyways.
What I personally want to do is somehow get rid of the 2 hooks this has, but I haven't figured out a way to do it yet =D.
Pleased to hear it, but I doubt it can be done. :)
So jesus4lyf, I promise that I will make the AIDS API work as it should, k?
Can you promise me to make this use AIDS instead? <3
There is honestly no reason not to. It is a good split up of functionality, too. :)

Hell, you'd be doing something I intended to do already...
 

Nestharus

o-o
Reaction score
84

Well... the events + access out of scope ; |. AIDS would actually have to change the core, otherwise you'd pretty much have to redo the deindexing AIDS already does so that you can capture the events in a standalone system ;o. I hope I'm making sense ; D.

AIDS can support that. I dare say it's not even too hard.
Think about it, every unit on the map has undefend already and an ID associated, which you know will not be removed before the unit. I intend, ideally, to add an AutoEvents port to AIDS, even, maybe.

Well aye. I personally used timestamps : D, lol. You need to hook the stuff that removes units because there's no way tell if a unit was removed while allowing people to access the unit before it goes out of scope and you need either timestamps (make sure timestamps aren't equal) or you need to run a timer with a time of 0 and go through an array and mark all the units for destruction the next time they go through removal. I preferred timestamps because I thought that was a bit more efficient.

Woah, wait. You totally didn't "see Damage" like I said. The point is the "takes damage" event is specific to the literal WC3 unit. Which means you're just gonna stuff up systems like that...

If a unit transforms, it is still regarded as the specific unit in the eyes of the player. There is the specific unit, and then the literal specific unit. Methinks damage should probably work on the specific rather than literal because literal might end up being paused somewhere or w/e if it's replaced with another unit o-o. I don't even know what you'd attach to the literal unit, lol...

Can you promise me to make this use AIDS instead?
There is honestly no reason not to. It is a good split up of functionality, too.

Hell, you'd be doing something I intended to do already...

Well, I did put quite a lot of time and effort into this and I mean, AIDS would have to change to a degree for me to want to make this use it... for example, I'm not digging the all global unit indexing/deindexing with condition functions... splitting them up into different triggers to reduce evaluations seems like a better design ; |.

Also, you can improve some of the stuff in AIDS too, which I hope you saw in my little AIDS API : P.

Well, we shall see. I really think the current design here is about as good as it can get (excluding the locks). This would not be well as an add on as everything this does is better done in the main lib I think ;\. I know the stuff like IsUnitDecayed and IsUnitAnimated seems really out of place, but the main lib is sadly where the fields are set : (. Yes, that means I think the timestamp option is a better choice than the loop undefend timer option ;p.

I'm probably just not thinking what you're thinking though = ).
 

Jesus4Lyf

Good Idea™
Reaction score
397
First, a side-note: I haven't read your code. I don't have time, yet. :p

Now, think outside the box reading AutoIndex code put you in.
I'm probably just not thinking what you're thinking though = ).
Right. AIDS currently does not monitor unit state. I'm thinking you write your own events system separate to AIDS, which attaches based on id, but provides its own OnIndexAllocate/OnIndexDeallocate events (whatever AutoEvents calls them). Ok, the OnIndexAllocate should hook into an AIDS struct AIDS_onCreate, but the on deallocate should be using the undefend magic. The point is if you use AIDS, recursion is already managed for the most part, your index allocation/deallocation is likewise, managed, and you don't need to worry about creating things like index locking yourself.

>AIDS would actually have to change the core, otherwise you'd pretty much have to redo the deindexing
Unit leaves map event is independent of the unit's index being freed. AIDS would need no such change.

AutoIndex and AIDS are philosophically different because I believe a unit's id is still useful after the unit has left the game (just like Blizzard does - a handle id is not recycled until you are actually done with references to it; similarly, in AIDS, you can lock structs to lock an index until you are finished with it). But that philosophy behind AIDS can support a super set of the functionality of AutoIndex, as it did at the time of release. If you'd like to bridge the gap with this system, and add some more stuff, feel free. The only thing I'm suggesting you use from AIDS is one AIDS_onCreate to hook the unit enters map event, and GetUnitId for attaching. And the fact that you won't need to implement undefend on all units yourself, since AIDS comes with it. :)

It means we finally have proper division between an indexer, and a unit states event system. AutoIndex couples them. :D
 

Nestharus

o-o
Reaction score
84
v2.0.0.0 is out.


It's extremely efficient : D. The deindexing is the fastest deindexing of all unit indexing systems at the moment.

Go through the list to see a quick overview of the features.
 

Hatebreeder

So many apples
Reaction score
381
v2.0.0.0 is out.


It's extremely efficient : D. The deindexing is the fastest deindexing of all unit indexing systems at the moment.

Go through the list to see a quick overview of the features.

Can you include Benchmarks compared to AIDS, please?
because, to me your statement has no solid backup ( I hope you know what I mean... ).
 

Sevion

The DIY Ninja
Reaction score
413
Nes, you should start benchmarking things first before saying "fastest" or anything dealing with that subject.
 

Nestharus

o-o
Reaction score
84
It's simply impossible for AIDS to be faster than this given its current code.

No benchmarks necessary -.-.

If you looked at the code, it would be extremely apparent..


This is the entire deindexing function for this
JASS:

//
    private function onUndefend takes nothing returns boolean
        local unit u = GetFilterUnit()
        if (GetUnitAbilityLevel(u, &#039;OUIN&#039;) == 0) then
            set indexed = GetUnitUserData(u)
            
            if (indexedUnit[indexed] == u) then
                
                if (onDeindex.hasCode) then
                    call onDeindex.fire()
                endif
                
                if (lock[indexed] == 0) then
                    set recycle[recycleCount] = indexed
                    set recycleCount = recycleCount + 1
                endif
                set indexedUnit[indexed] = null
            endif
        endif
        set u = null
        return false
    endfunction


And that is a filter...

AIDS is 1 timer that runs a function, 1 filter, and one trigger condition.

As you can see, there is simply no comparison. The code I have here is about the minimal you can do (obviously you could take out the locking).
 

Romek

Super Moderator
Reaction score
963
> The deindexing is the fastest deindexing...
How about the indexing? And by how many nanoseconds difference are we talking? :p
I don't think such insignificant speed differences matter when there's a lack of features (perhaps that's why this is 'fast').

> all unit indexing systems at the moment.
All three of them?
 

Sevion

The DIY Ninja
Reaction score
413
It's simply impossible for AIDS to be faster than this given its current code.

No benchmarks necessary -.-.

If you looked at the code, it would be extremely apparent..

This is not a valid excuse.

Besides, I don't think a few nanoseconds is really a big deal.

Times like these, I agree with Romek, features far outweigh speed when it's so insignificant.
 

Nestharus

o-o
Reaction score
84
This has the same features as AIDS and more for actual indexing ; |... but this does not have manual indexing, but the GetUnitIndex in the AIDS API will work just like AIDS = ).

Also, event stuff shouldn't be coupled with an indexing library.

I agree that a few nanoseconds doesn't matter, but if you are given the same features and a few more like being able to access a unit right before it goes out of scope, then I think the choice is obvious ; |.

I'm not saying this should replace everything, I'm just saying that this is another alternative. I'd choose this alternative myself, and as I say, I will def support an AIDS and PUI API. I will never support AutoIndex API because I plainly don't condone it : P. AutoIndex is evil, haha.
 
Status
Not open for further replies.
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Members online

      No members online now.

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top