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

GUI Unit Indexer 1.4.0.0

Why Unit Indexing is Important


For those not familiar with unit indexers such as UnitIndexingUtils, AutoIndex,
Perfect Unit Indexing (PUI), Advanced Indexing and Data Storage (AIDS) or
Unit Indexer, this can give you a bit of a crash-course.

You definitely want to make your spell MUI. To do that, you either use a hashtable or use some
complex form of indexing. It is very good to choose hashtable because you can load data
from a unit instead of from a list (ie. making it very easy to retrieve an index on death).

Using a hashtable has a bit of a learning curve. There are two keys - a child key, a
parent key and, finally, the actual data being stored. Saving 100 to the casting
unit looks like this:

  • Hashtable - Save 100 as (Key(Damage)) of (Key(Triggering unit)) in (Last created hashtable)
Using a unit indexer, you can super-simplify it to just this:

  • Set Damage[(Custom value of (Triggering unit))] = 100
Instead of using a hashtable with multiple keys, this simply uses an array with the
custom value of the unit as the array index.

Have you ever used unit custom value before? If so, you may be familiar with this method:

  • Unit - Set custom value of (Triggering unit) to 100
That is definitely the easiest way to attach 100 to the unit, but you really limit yourself
by doing that. What if you wanted to remember other things, such as the target unit and the
target location?

Using a Unit Indexer, it's like this:

  • Set Key = (Custom value of (Triggering unit))
  • Set Damage[Key] = 100
  • Set Target[Key] = (Target unit of ability being cast)
  • Set TargetPoint[Key] = (Target point of ability being cast)
  • Unit Group - Add (Triggering unit) to SpellGroup
Recalling this data whenever you want becomes truly easy and even easy to read.

  • Timed Spell
    • Events
      • Time - Every 0.03 seconds of game time
    • Conditions
    • Actions
      • Unit Group - Pick every unit in SpellGroup and do (Actions)
        • Loop - Actions
          • Set Key = (Custom value of (Picked unit))
          • Unit - Cause (Picked unit) to damage Target[Key] for Damage[Key] of attack type Chaos and damage type normal
The possiblities are literally endless. Indexing this way is pretty fun as well, even helping
to reduce total in-game hashtable count (the limit is 256).


Requiring no NewGen, JassHelper or even knowledge of JASS, this is the easiest unit indexer
to install into a map and start using to its fullest right away.
  1. Make sure "automatically create variables" is checked under "File -> Preferences"
  2. Copy and paste the following trigger (from the test map)
  3. It's installed!

  • Unit Indexer
    • Events
      • Map initialization
    • Conditions
    • Actions
      • Custom script: call ExecuteFunc("InitializeUnitIndexer")
      • Custom script: endfunction
      • -------- --------
      • -------- This is the core function - it provides an index all existing units and for units as they enter the map --------
      • -------- --------
      • Custom script: function IndexUnit takes nothing returns boolean
      • Custom script: local integer pdex = udg_UDex
      • Custom script: local integer ndex
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • IsUnitPreplaced[0] Equal to False
        • Then - Actions
          • -------- --------
          • -------- Check for removed units for every (32) new units created --------
          • -------- --------
          • Set UDexWasted = (UDexWasted + 1)
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • UDexWasted Equal to 32
            • Then - Actions
              • Set UDexWasted = 0
              • Set UDex = UDexNext[0]
              • Custom script: loop
              • Custom script: exitwhen udg_UDex == 0
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • (Custom value of UDexUnits[UDex]) Equal to 0
                • Then - Actions
                  • -------- --------
                  • -------- Remove index from linked list --------
                  • -------- --------
                  • Custom script: set ndex = udg_UDexNext[udg_UDex]
                  • Custom script: set udg_UDexNext[udg_UDexPrev[udg_UDex]] = ndex
                  • Custom script: set udg_UDexPrev[ndex] = udg_UDexPrev[udg_UDex]
                  • Set UDexPrev[UDex] = 0
                  • Set IsUnitPreplaced[UDex] = False
                  • -------- --------
                  • -------- Fire deindex event for UDex --------
                  • -------- --------
                  • Set UnitIndexEvent = 2.00
                  • Set UnitIndexEvent = 0.00
                  • -------- --------
                  • -------- Recycle the index for later use --------
                  • -------- --------
                  • Set UDexUnits[UDex] = No unit
                  • Set UDexNext[UDex] = UDexRecycle
                  • Set UDexRecycle = UDex
                  • Custom script: set udg_UDex = ndex
                • Else - Actions
                  • Set UDex = UDexNext[UDex]
              • Custom script: endloop
            • Else - Actions
        • Else - Actions
      • -------- --------
      • -------- You can use the boolean UnitIndexerEnabled to protect some of your undesirable units from being indexed --------
      • -------- - Example: --------
      • -------- -- Set UnitIndexerEnabled = False --------
      • -------- -- Unit - Create 1 Dummy for (Triggering player) at TempLoc facing 0.00 degrees --------
      • -------- -- Set UnitIndexerEnabled = True --------
      • -------- --------
      • -------- You can also customize the following block - if conditions are false the (Matching unit) won't be indexed. --------
      • -------- --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • UnitIndexerEnabled Equal to True
          • (Custom value of (Matching unit)) Equal to 0
        • Then - Actions
          • -------- --------
          • -------- Generate a unique integer index for this unit --------
          • -------- --------
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • UDexRecycle Equal to 0
            • Then - Actions
              • Set UDex = (UDexGen + 1)
              • Set UDexGen = UDex
            • Else - Actions
              • Set UDex = UDexRecycle
              • Set UDexRecycle = UDexNext[UDex]
          • -------- --------
          • -------- Link index to unit, unit to index --------
          • -------- --------
          • Set UDexUnits[UDex] = (Matching unit)
          • Unit - Set the custom value of UDexUnits[UDex] to UDex
          • Set IsUnitPreplaced[UDex] = IsUnitPreplaced[0]
          • -------- --------
          • -------- Use a doubly-linked list to store all active indexes --------
          • -------- --------
          • Set UDexPrev[UDexNext[0]] = UDex
          • Set UDexNext[UDex] = UDexNext[0]
          • Set UDexNext[0] = UDex
          • -------- --------
          • -------- Fire index event for UDex --------
          • -------- --------
          • Set UnitIndexEvent = 0.00
          • Set UnitIndexEvent = 1.00
          • Set UnitIndexEvent = 0.00
        • Else - Actions
      • Custom script: set udg_UDex = pdex
      • Custom script: return false
      • Custom script: endfunction
      • -------- --------
      • -------- The next function initializes the core of the system --------
      • -------- --------
      • Custom script: function InitializeUnitIndexer takes nothing returns nothing
      • Custom script: local integer i = 0
      • Custom script: local region re = CreateRegion()
      • Custom script: local rect r = GetWorldBounds()
      • Custom script: local boolexpr b = Filter(function IndexUnit)
      • Set UnitIndexEvent = -1.00
      • Set UnitIndexerEnabled = True
      • Set IsUnitPreplaced[0] = True
      • Custom script: call RegionAddRect(re, r)
      • Custom script: call TriggerRegisterEnterRegion(CreateTrigger(), re, b)
      • Custom script: call RemoveRect(r)
      • Custom script: set re = null
      • Custom script: set r = null
      • Custom script: loop
      • Custom script: call GroupEnumUnitsOfPlayer(bj_lastCreatedGroup, Player(i), b)
      • Custom script: set i = i + 1
      • Custom script: exitwhen i == bj_MAX_PLAYER_SLOTS
      • Custom script: endloop
      • Custom script: set b = null
      • -------- --------
      • -------- This is the "Unit Indexer Initialized" event, use it instead of "Map Initialization" for best results --------
      • -------- --------
      • Set IsUnitPreplaced[0] = False
      • Set UnitIndexEvent = 3.00

So if you want to have an event fire when a unit is created, when it is leaves the game, or when the unit indexer is initialized, you should take advantage of the UnitIndexEvent real variable.

  • Unit Indexed Event
    • Events
      • Game - UnitIndexEvent becomes Equal to 1.00
    • Conditions
      • UDexUnits[UDex] is A Hero Equal To true
    • Actions
      • Item - Create 1 Tome of Power and give it to UDexUnits[UDex]
  • Unit Deindexed Event
    • Events
      • Game - UnitIndexEvent becomes Equal to 2.00
    • Conditions
    • Actions
      • Game - Display to (All Players) the text - Unit (UDex) was deindexed!
  • Unit Indexer Initialized Event
    • Events
      • Game - UnitIndexEvent becomes Equal to 3.00
    • Conditions
    • Actions
      • Unit - Create 1 Paladin for (Player 1) at TempPoint facing 0.00 degrees
      • Item - Create 1 Ankh of Reincarnation and give it to (Last created unit)
      • Set HeroItem[(Custom value of (Last created unit))] = (Last created item)

Thanks
Nestharus for creating the powerful vJass UnitIndexer.
The community for encouraging me to use a unit indexer when I was learning.​

Examples of scripts using this

Pros
  • Gives units a unique custom value for use as array indexes (1-8190)
  • Recycles indexes of decayed/removed units
  • Very extensible library that can be used for not just spells but systems as well.
  • Extremely easy to implement (cnp)
  • No object editor data needed
  • Does not need a timer
  • No knowledge of JASS required. You can toggle the boolean UnitIndexerEnabled to filter unwanted units, and you can even customize the filter with more conditions than just that if you want to do something like filter summoned units or not allow any units to be indexed with locust, for example.
  • Has "OnIndex" (UnitIndexEvent == 1.00) and "OnDeindex" (UnitIndexEvent == 2.00) events
Cons
  • You can only get the custom value of units, not set it. Work with the unit indexer - not
    against it. You can easily create an array and reference all the data you need (custom value of unit as the array index) instead of using custom value directly.
  • Use the event - "Game - UnitIndexEvent Equal to 3.00" instead of "Map Initialization" if you want to make sure all of your units have custom value when used in that trigger's actions.
  • Units are not "in scope" when deindexed, so things like checking if it's summoned or if it's a hero will not work. Use the seperate resource "Unit Event" with the event "DeathEvent becomes Equal to 3.00" to catch a unit as soon as it's removed.
Keywords:
unit indexer, custom value, aids, autoindex, getunituserdata, unituserdata, mui, indexing, is unit moving, unitindexer, indexer, index, id generator,
Contents

GUI Unit Indexer Testmap (Map)

Reviews
16:29, 28th Jun 2011 Maker: Approved. Can be of great use in creating MUI spells and systems.
Level 5
Joined
Oct 12, 2004
Messages
109
what do you mean an extension? and I just copy and pasted the trigger and had auto copy variables on. The system works, it just adds an ability to all of my buildings I build. And when I disable the trigger that ability is gone so it's definitely the unit indexer giving my buildings the ability.
 
Level 5
Joined
Oct 12, 2004
Messages
109
hmm. this is the first trigger i have copy and pasted into the map. everything else is done by me. it's weird because when i disable the Unit Indexer Trigger it doesn't give the ability to my buildings.
 

Deleted member 219079

D

Deleted member 219079

Thank you for creating this index system, it will help me to get started with spell making (I'm sure my spell will get approved on first release when it's using this :grin:)
 
best system ever. <-- so i could rate a 5/5 ^^

Could you explain to the noob me, what this system usefull for? from the description I saw he enters a unit into a group that in which, a unit damages another unit.
Each unit in Unitgroup{
Damage specific target
}
So basicly this system does single unit damage?

And why doesnt it work for me when I put 300+ units? I used the display command and everything, is this limited or floating text is the limited?
 
There can only be 100 floating texts at a given time.

That explains :D oh and by the way I learned a bit how to use it, wow
wow
wow - ow
WOW this thing is usefull
Having random units never disapear from memory
Having uncatchable events to happen with godly touch
Create unit? set Systemon = False
create unit
set Systemon = True
Need to do something after 300 seconds to many units ?
create 1 unit
set system off
give custom value like the target unit
set system off
give 300 secs of timed life
add unit to event

event ^ unit^ dies
set ug = all units with custom value like dead unit, not include dummies
set unit = picked unit
call remove group

====== UNIT IS NOW CONTROLLEDABLE ======
WOW
:thumbs_up::thumbs_up::thumbs_up::thumbs_up::thumbs_up::thumbs_up:
5/5 HIGHLY RECOMMANDED
 
Level 6
Joined
Nov 12, 2012
Messages
153
Woah man...

This is great. Right now I'm learning how to use hashtables to make spells. I know, this is my opinion, but I preffer using hashtables right now, just to really learn it (The hard way), before using this amazing system (the not-hard way).

Really, thanks for this... 5/5
 
That explains :D oh and by the way I learned a bit how to use it, wow
wow
wow - ow
WOW this thing is usefull
Having random units never disapear from memory
Having uncatchable events to happen with godly touch
Create unit? set Systemon = False
create unit
set Systemon = True
Need to do something after 300 seconds to many units ?
create 1 unit
set system off
give custom value like the target unit
set system off
give 300 secs of timed life
add unit to event

event ^ unit^ dies
set ug = all units with custom value like dead unit, not include dummies
set unit = picked unit
call remove group

====== UNIT IS NOW CONTROLLEDABLE ======
WOW
:thumbs_up::thumbs_up::thumbs_up::thumbs_up::thumbs_up::thumbs_up:
5/5 HIGHLY RECOMMANDED
------ 1 year later ------
I KNOW HASHTABLE, THIS SYSTEM IS USELESS AND NOBODY IS GOING TO NEED IT, EVER.
BUT. SINCE YOU CAN SEE THAT FOR THOSE WHO DONT KNOW HASHTABLE THIS MIGHT AS WELL BE A LIFESAVER, I RECOMMAND LEAVE IT BE, FOR NOOBIES SAKE.
HASHTABLES EASIER TO USE AND LESS COMPLAX, ONCE YOU LEARNED HOW TO USE THEM, THIS, HOWEVER, MAKE UNIT[CORRENT UNITS IN EXISTENCE] WHICH IS OBVIOUSLY LAGGIER, BUT FOR THOSE WHO LEARN EDITOR FOR THE FIRST TIME, IT IS REALLY HELPFULL.
KNOW HASHTABLE? 0/5 NOT RECOMMANDED.
DUNNO HASHTABLE? 5/5 RECOMMANDED.
 
Level 23
Joined
Apr 16, 2012
Messages
4,041
NEVER underestimate UnitIndexer, it's 60% faster than hashtables and it's highly recommended in making spells, hashtables will break if you have more than 255 in your map...

If people were smart enough to use one single hashtable for everything, there would be no problem. One person was smart enough to create resource based on this, its in vJass, but still: http://www.hiveworkshop.com/forums/jass-resources-412/snippet-new-table-188084/

Hashtables have their pros and cons, as do Unit indexers.
 

Deleted member 219079

D

Deleted member 219079

Nice for vanilla JASS spells too :)
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,468
How does it know a unit is to be Deindexed? Is it when the custom value of the unit is 0?

Yes. When a unit is removed from play, its custom value and Unit Type Id become 0. This system doesn't give a precise time of removal on its own, as I just do the check when a new index is needed.

If you use Unit Event, you get more interesting things like a unit removal or unit reincarnation stuff.
 
There's a quite peculiar problem that I've encountered. I've made a DeathEvent trigger for a unit; and at the same time, I make a spell using the GUI Spell System. What this spell does is casting 4-12 Carrion Swarms with 0.05s interval between each (it looks like hurling a wave of shurikens). But when a unit is killed by this spell at very close range (where it eats all of the shurikens) the actions of that unit's DeathEvent trigger would not be called.
 
Level 2
Joined
Jul 8, 2017
Messages
17
Hi, I need a bit of help clarifying a couple of points because it's unclear to me:

1. From what I've read, you basically can attach any specific data to any unit and refer to each of the data accurately. If so, is it possible to refer to the unit when it dies and if so, how? Via the 'UnitIndexEvent becomes equal to 2.00'?

2. What variables do I use/not touch? I'm a little confused because of the names of the variables and that it doesn't really coincide with the example in the crash course. From what I can tell, UDex is for the custom value of the unit, but I'm a bit lost as to what to do from there.
 
Last edited:
Level 2
Joined
Jul 8, 2017
Messages
17
Okay, I think I finally wrapped my head around how it works now.

1 more question for now: Do you recommend creating a new variable and setting it to the custom value of the unit, or use the existing variable UDex and just work with it, seeing as it already has the custom value attached to it?

I hope I'm not hassling you too much :(

Thank you for the response!
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,468
Here's the thing: an event is a single moment in time. It lasts for one thread (measured in nanoseconds). As soon as that moment has passed, the variables such as UDex default to 0 or whatever. Variables such as UDexUnits[] won't change, so all you need to remember is UDex (using another storage method like a List, Hashtable, whatever, or just get the custom value of whatever unit you need whenever you need.
 
Level 5
Joined
Apr 10, 2011
Messages
56
I am having a weird issue when units are created on the map. For some reason the health of any unit created is set to 500,000. I sifted through the code and obtained the Unit Indexer in your Damage System. I am currently using your Damage System 4.0. I had the similar issue with 3.8 also, but thought it might be trigger incompatibility.
Either way, not sure what is causing this and it has completely stunted my map making progress because I do not want to trigger too much if I can not remove this issue. Thanks
 
Level 5
Joined
Apr 10, 2011
Messages
56
Yes I am not sure of the exact issue, but it was definitely triggers and how I was referencing arrays. I since deleted all my code and reinstalled your systems. So thanks! You are allowing me to build something truly beautiful with flat damage instead of percent based damage. My new issue was all my structures were exploding on map start up.

Found it was was an unset index issue:
Unit - Set Max HP of myUnit to ((Integer(myStatHP[UDex])) x 2)
Sadly my buildings have myStatHP[UDex] set to 0 by default. It was truly a funny bug to see, but yes I fixed that by just ignoring the trigger if UDexUnits[UDex] is a Structure.

Your code is great. Thanks!
 
Level 5
Joined
Apr 10, 2011
Messages
56
Do you happen to know the best way to keep track of all of the Structures (buildings) in the Unit Indexer? I can not seem to figure that out without iterating over the whole Unit Indexer and checking if Unit is a Structure. That seems to be a very heavy operation when a lot of units are on the map. Any insight would be greatly appreciated! Thanks.
 
Level 9
Joined
May 24, 2016
Messages
298
So, this is a gui version. It's also a vjass nearby? (And could a vanilla user use that)
Why indexer is so worthy to use? Okay its simpler than saving all things in hash, but does hash has some restrictions?

I never thought is it simple to change my coding style, from going to bribe damage detection (instead of looking for help system where I stored much functions), and using indexer instead of hash.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,468
So, this is a gui version. It's also a vjass nearby? (And could a vanilla user use that)
Why indexer is so worthy to use? Okay its simpler than saving all things in hash, but does hash has some restrictions?

I never thought is it simple to change my coding style, from going to bribe damage detection (instead of looking for help system where I stored much functions), and using indexer instead of hash.

You don't need Unit Indexer to use Damage Engine, unless you're using an old version of it.
 
Level 7
Joined
Jul 4, 2007
Messages
249
In what way is this easier/more useful than just using hashtables? I don't get it, isn't it basically the same?
 
Top