1. Updated Resource Submission Rules: All model & skin resource submissions must now include an in-game screenshot. This is to help speed up the moderation process and to show how the model and/or texture looks like from the in-game camera.
    Dismiss Notice
  2. DID YOU KNOW - That you can unlock new rank icons by posting on the forums or winning contests? Click here to customize your rank or read our User Rank Policy to see a list of ranks that you can unlock. Have you won a contest and still havn't received your rank award? Then please contact the administration.
    Dismiss Notice
  3. The poll for Hive's 12th Concept Art Contest is up! Go cast your vote for your favourite genie!
    Dismiss Notice
  4. Travel to distant realms and encounter scenes unknown to the common folk. The Greatest of Adventures is upon us with the 8th Cinematic Contest. Join in on a fun ride.
    Dismiss Notice
  5. The 18th Icon Contest is ON! Choose any ingame unit and give him/her Hero abilities. Good luck to all.
    Dismiss Notice
  6. Contestants are to create a scene set in the Stone Age. Come and see what you can come up with. We wish you the best of luck!
    Dismiss Notice
  7. Colour outside the lines! Techtree Contest #13 is a go. The contest is optionally paired.
    Dismiss Notice
  8. Greetings cerebrates, our Swarm needs new spawners that will have numerous children. Join the HIVE's 31st Modeling Contest - Spawners and Spawned! The contest is optionally paired.
    Dismiss Notice
  9. Check out the Staff job openings thread.
    Dismiss Notice
Dismiss Notice
60,000 passwords have been reset on July 8, 2019. If you cannot login, read this.

[vJASS] My Unit Indexer

Discussion in 'Triggers & Scripts' started by Krogoth, Oct 18, 2012.

  1. Krogoth

    Krogoth

    Joined:
    Apr 5, 2011
    Messages:
    247
    Resources:
    0
    Resources:
    0
    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:
    Code (vJASS):
    //======================
    //=======[ 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:
    Code (vJASS):
    //==============
    //=== 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
     

    Attached Files:

    Last edited: Oct 19, 2012
  2. PurgeandFire

    PurgeandFire

    Code Moderator

    Joined:
    Nov 11, 2006
    Messages:
    7,427
    Resources:
    18
    Icons:
    1
    Spells:
    4
    Tutorials:
    9
    JASS:
    4
    Resources:
    18
    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.
     
  3. Krogoth

    Krogoth

    Joined:
    Apr 5, 2011
    Messages:
    247
    Resources:
    0
    Resources:
    0
    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: Oct 19, 2012
  4. PurgeandFire

    PurgeandFire

    Code Moderator

    Joined:
    Nov 11, 2006
    Messages:
    7,427
    Resources:
    18
    Icons:
    1
    Spells:
    4
    Tutorials:
    9
    JASS:
    4
    Resources:
    18
    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.
     
  5. Anachron

    Anachron

    Joined:
    Sep 9, 2007
    Messages:
    6,167
    Resources:
    66
    Icons:
    49
    Packs:
    2
    Tools:
    1
    Maps:
    3
    Spells:
    9
    Tutorials:
    1
    JASS:
    1
    Resources:
    66
    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.
     
  6. Krogoth

    Krogoth

    Joined:
    Apr 5, 2011
    Messages:
    247
    Resources:
    0
    Resources:
    0
    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.