• 🏆 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] My Unit Indexer

Status
Not open for further replies.
Level 7
Joined
Apr 5, 2011
Messages
245
There is an auto unit indexer in demo map below in attachments. I called it Very Simple Unit Indexer because it is very simple in my op. It's very short, check it please. (Look at trigger "vSUI" or just below) What really hurts me now it's using death event for unregister. (!) What kind of problems can it cause?

edit
vSUI -> vGUI.

vSUI code:
JASS:
//======================
//=======[ vGUI ]=======
//======= v0.104 =======

library vGUI uses IndexedData, NExt, WorldBounds, optional Temple

//=== Settings ===
globals
    private constant boolean INSTANT_INIT = true
    private constant boolean REGISTER_START_UNITS = true
//----------------
    private constant boolean DAMAGE_CONTROLLER = true
    private constant integer REFRESH_COUNT = 15
    //When <REFRESH_COUNT> units are registered damage trigger refreshes itself.
//----------------
    private constant boolean TEST_MODE = true
endglobals
//================

    globals
        indexedUnit Unit
    endglobals

    struct vGDC
        readonly static boolean enabled = false
        private static trigger t
        private static integer count = 0

        method register takes unit u returns nothing
                //Register damage event
                call TriggerRegisterUnitEvent(damageController, u, EVENT_UNIT_DAMAGED)
                //Count registered units to refresh damage trigger one fine day
                set count = count + 1
                if count == REFRESH_COUNT then
                    set count = 0
                    call refresh()
                endif
        endfunction

        //=== Upon unit takes damage ===
        private static method onDamage takes nothing returns boolean
            local unit damaged = GetTriggerUnit()
            local unit damager = GetEventDamageSource()
            local real damage = GetEventDamage()
            //Test
            static if TEST_MODE then
                call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "Unit[" + I2S(Unit.indexOf(damaged)) + "] takes " + R2S(damage) + " damage from Unit[" + I2S(Unit.indexOf(damager)) + "]")
            endif
            //Send 1 templar
            static if LIBRARY_Temple then
                call onUnitTakesDamage(damaged, damager, damage)
            endif
            set damaged = null
            set damager = null
            return false
        endmethod

    endstruct

    struct vGUI
        readonly static boolean enabled = false
        private static trigger enterTrigger
        private static trigger deathTrigger

        //=== Register filtered unit ===
        private static method register takes nothing returns boolean
            local unit u = GetFilterUnit()
            call Unit.register(u)
            //Test
            static if TEST_MODE then
                call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "Unit[" + I2S(GetUnitUserData(u)) + "] has been registered.")
            endif
            //Register unit for damage controller
            static if DAMAGE_CONTROLLER then
                call vGDC.register(u)
            endif
            //Send 1 templar
            static if LIBRARY_Temple then
                call onUnitRegister(u)
            endif
            set u = null
            return false
        endmethod

        //=== Unregister filtered unit ===
        private static method unregister takes nothing returns boolean
            local unit u = GetTriggerUnit()
            call Unit.unregister(u)
            //Test
            static if TEST_MODE then
                call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "Unit[" + I2S(GetUnitUserData(u)) + "] has been unregistered.")
            endif
            //Send 1 templar
            static if LIBRARY_Temple then
                call onUnitUnregister(u)
            endif
            set u = null
            return false
        endmethod

        //=== Register all units present at this moment ===
        static method snapshot takes nothing returns nothing
            local group g = CreateGroup()
            call GroupEnumUnits(g, Condition(function thistype.register))
            call DestroyGroup(g)
            set g = null
        endmethod        

        //=== Enable/disable dynamic register ===
        static method turn takes boolean flag returns nothing
            if flag then
                call EnableTrigger(enterTrigger)
                call EnableTrigger(deathTrigger)
                set enabled = true
            else
                call DisableTrigger(enterTrigger)
                call DisableTrigger(deathTrigger)
                set enabled = false
            endif
        endmethod

        //=== Refresh damage trigger ===
        private static method refresh takes nothing returns nothing
            local integer i = 0
            //Clear triggers
            call DestroyTrigger(damageController)
            set damageController = CreateTrigger()
            call TriggerAddCondition(damageController, Condition(function thistype.onDamage))
            //Restore events
            loop
                exitwhen i == Unit.size
                if Unit[i] != null then
                    call TriggerRegisterUnitEvent(damageController, Unit[i], EVENT_UNIT_DAMAGED)
                endif
                set i = i + 1
            endloop
        endmethod

        //=== Enable/disable damage controller ===
        static method turnDC takes boolean flag returns nothing
            if flag then
                call EnableTrigger(damageController)
                set DC_enabled = true
            else
                call DisableTrigger(damageController)
                set DC_enabled = false
            endif
        endmethod
    endif

        //=== Starts work with it ===
        static method start takes nothing returns nothing
            //Create all needed dynamic variables if it has not been done at struct init
            static if not INSTANT_INIT then
                set Unit = Unit.create()
                set enterTrigger = CreateTrigger()
                set deathTrigger = CreateTrigger()
                static if DAMAGE_CONTROLLER then
                    set damageController = CreateTrigger()
                endif
            endif
            //Register all present units if it is needed
            static if REGISTER_START_UNITS then
                call snapshot()
            endif
            //Enable dynamic register
            call TriggerRegisterEnterRegion(enterTrigger, WorldBounds.worldRegion, Condition(function thistype.register))
            set enabled = true
            call TriggerAddCondition(deathTrigger, Condition(function thistype.unregister))
            //Enable damage controller if it is needed
            static if DAMAGE_CONTROLLER then
                call TriggerAddCondition(damageController, Condition(function thistype.onDamage))
                set damageControl = true
            endif
        endmethod
        
        static method onInit takes nothing returns nothing
            //Create all needed dynamic variables if vGUI init is set instant
            static if INSTANT_INIT then
                set Unit = Unit.create()
                set enterTrigger = CreateTrigger()
                set deathTrigger = CreateTrigger()
                static if DAMAGE_CONTROLLER then
                    set damageController = CreateTrigger()
                endif
            endif
        endmethod
    endstruct
endlibrary
Temple:
JASS:
//==============
//=== Temple ===
//==============

library Temple

function onUnitRegister takes unit u returns nothing
endfunction

function onUnitUnregister takes unit u returns nothing
endfunction

function onUnitTakesDamage takes unit damaged, unit damager, real damage returns nothing
endfunction

endlibrary
 

Attachments

  • KrogothUnitIndexer.w3x
    36.2 KB · Views: 35
  • KrogothUnitIndexer2.w3x
    38.6 KB · Views: 32
Last edited:
The problem is that if a unit is removed from the map (not killed, just removed) then he'll still be indexed. It won't fire the unregister.

However, since you are just coding for your map, I just recommend that you avoid RemoveUnit when you can. If you do want to use it, then add a custom method to unregister or just make a custom RemoveUnit() to unregister and use that instead.

Alternatively, you can hook RemoveUnit but that is a bit slower due to trigger evaluations. Usually, UnitIndexers will use an ability but idk, in your own map you probably can just make the changes as I've said above and you should be fine.
 
Level 7
Joined
Apr 5, 2011
Messages
245
That's ok, I prefer to killing anyway.

added
I have used TriggerRegisterUnitEvent with actions instead of TriggerRegisterPlayerUnitEvent with condition for unregister upon death. So, when unit is registered new action is created. Is it worse?

added
Pros is that it will be refreshed (old actions removed) with damage trigger both.

added
Made conditions. Do not know why did I use actions. Something wrong with me. :/
 
Last edited:
TriggerRegisterAnyUnitEventBJ() would be better. Whenever you register an event, you create a handle. So TriggerRegisterAnyUnitEventBJ() for death would lead to only 12 handles whereas registering for each units will create n unit events, where n is the number of units registered. (which often reaches hundreds or sometimes thousands)

You can't do that with the damage event but you can with the death event.
 
Why do you all make it so complicated?
I would add them to a table and then check every 30 or 60 seconds if they are alive, and if not, remove them from system.
Which map creates 10000 units in a minute so it matters to clear them more?
Or well, you could even make the check interval configureable. (or make a timer which runs every (amount of units in queue * 0.01) seconds or so... So it won't get slower with more units. Or make one that is running all the time and checks one unit by time (or up to 10) and uses smaller intervals.

Whatever you are doing, hooking functions is really ugly in my eyes.
 
Level 7
Joined
Apr 5, 2011
Messages
245
Death event is used in a lot of spells, so I have not made something over when used trigger for it. Global trigger should be used. That's why that timer that ticks ticks clears or registered units calculation or something else which is not even as sharp as death event, I think this all is not efficient. (Correct me if I'm wrong at this point) This system is compatible only with itself, but it provides easy interface to work with it, Template module where all events are. (No SpellEvent systems needed or something else) Now this systems consist of indexer and [wip] damage controller.
 
Status
Not open for further replies.
Top