1. Head to the 33rd Modeling Contest Poll and drink to your heart's desire.
    Dismiss Notice
  2. Choose your means of doom in the 17th Mini Mapping Contest Poll.
    Dismiss Notice
  3. A slave to two rhythms, the 22nd Terraining Contest is here.
    Dismiss Notice
  4. The heavens smile on the old faithful. The 16th Techtree Contest has begun.
    Dismiss Notice
  5. The die is cast - the 6th Melee Mapping Contest results have been announced. Onward to the Hive Cup!
    Dismiss Notice
  6. The glory of the 20th Icon Contest is yours for the taking!
    Dismiss Notice
  7. 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.

[JASS] Global Group Problem

Discussion in 'Triggers & Scripts' started by Narg666, Dec 6, 2012.

  1. Narg666

    Narg666

    Joined:
    Aug 30, 2009
    Messages:
    112
    Resources:
    0
    Resources:
    0
    Hi there, I need some help understanding why is this causing lag when multiple enemy units are targeted...

    Code (vJASS):
    scope RainOfChaos initializer Init

    private function Cond1 takes nothing returns boolean
            return(GetUnitState(GetFilterUnit(), UNIT_STATE_LIFE) > 0 and GetUnitAbilityLevel(GetFilterUnit(), 'Aloc') == 0 and GetUnitAbilityLevel(GetFilterUnit(), 'B012') > 0)
    endfunction

    private function Cond2 takes nothing returns boolean
            return(GetUnitState(GetFilterUnit(), UNIT_STATE_LIFE) > 0 and GetUnitAbilityLevel(GetFilterUnit(), 'Aloc') == 0 and IsUnitEnemy(GetFilterUnit(), GetOwningPlayer(GetEnumUnit())) and GetUnitAbilityLevel(GetFilterUnit(), 'A044') > 0)
    endfunction

    private function GroupAct takes nothing returns nothing
        local unit U = GetEnumUnit()
        local location L = GetUnitLoc(U)
        local group G = CreateGroup()
        local unit T
        local real Dmg = 30.00
        local effect Fx
        call GroupEnumUnitsInRangeOfLoc(G, L, 600.00, Condition(function Cond2))
        set T = FirstOfGroup(G)
        if T != null then
            set Dmg = Dmg * CountUnitsInGroup(G)
            set Fx = AddSpecialEffectTarget("Abilities\\Spells\\NightElf\\Immolation\\ImmolationDamage.mdl", U, "head")
            call UnitDamageTargetEx(T, U, Dmg, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_SPELL, false)
            call DestroyEffect(Fx)
        endif
        set T = null
        call DestroyGroup(G)
        call RemoveLocation(L)
        set U = null
    endfunction

    private function Actions takes nothing returns nothing
        local group Gr = CreateGroup()
        call GroupEnumUnitsInRect(Gr, GetPlayableMapRect(), Condition(function Cond1))
        call ForGroup(Gr, function GroupAct)
        call DestroyGroup(Gr)
    endfunction

    ////////////////////////////////////////////////////////////////////////////////////////////

    private function LearnAct takes nothing returns nothing
        local timer T = CreateTimer()
        call TimerStart(T, 1.00, true, function Actions)
       
        set T = null
        call DestroyTrigger(GetTriggeringTrigger())
    endfunction

    private function LearnCond takes nothing returns boolean
        return GetLearnedSkill() == 'A03H'
    endfunction

    private function Init takes nothing returns nothing
        local trigger T = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(T, EVENT_PLAYER_HERO_SKILL)
        call TriggerAddCondition(T, Condition(function LearnCond))
        call TriggerAddAction(T, function LearnAct)
        set T = null
    endfunction

    ////////////////////////////////////////////////////////////////////////////////////////////
    endscope


    Everything works fine, Infernals with stacking Permanent Immolation aura, but when I come across many enemy units, it lags!!!

    I've downloaded many maps that uses global grouping like I did, and none of them lag...

    Can anyone tell me if I'm doing something wrong? Or just give me some solution? Please, don't give the solution to the spell itself, there are many different ways I could be using to create a stacking permanent immolation, but what I want is to UNDERSTAND why is it lagging and how can I fix it!!!

    I heard about aura struct, that it could be able to target many units I want at once without lagging, is that right? And what is the difference between it and what I'm doing?

    Thank you.
     
  2. Almia

    Almia

    Joined:
    Apr 24, 2012
    Messages:
    4,842
    Resources:
    35
    Spells:
    30
    Tutorials:
    4
    JASS:
    1
    Resources:
    35
    First,you must null the group.
    Code (vJASS):
    set G = null
    set GR = null

    Second,All of the JASS types should be nulled,except reals,integers,strings etc.
    So the SFX,Location,Group etc should be nulled.

    Tips:
    Using EnumUnitsInRangeofLoc is very bad,also for Group.Just use EnumUnitsInRange and use plane coordinates instead.
    In vJASS,we have to use Coordinates instead of Locations because we are using JASS.(Coordinates(x,y) are much faster and leakless than locations)

    Also,Your Script is somewhat like converted from GUI to JASS then changed those names of the functions and just added a scope.Are you a beginner?

    Also use Library instead of Scope.And also use Struct
     
  3. Narg666

    Narg666

    Joined:
    Aug 30, 2009
    Messages:
    112
    Resources:
    0
    Resources:
    0
    Yes, I'm a beginner, I'm trying to understand and learn vJass.

    How can I use library or struct instead of scope???

    I've seen many maps created by scripters who use scope.

    I have many snippets in my map, does it lag too?


    **EDIT **

    I did what you said, it have reduced the lag, but is still lagging every 1 sec when nearby many enemy units, do you have any other ideas?

    Thank you for your help already, I'm very grateful
     
    Last edited: Dec 6, 2012
  4. -Kobas-

    -Kobas-

    Joined:
    Jan 17, 2010
    Messages:
    5,892
    Resources:
    28
    Icons:
    1
    Tools:
    2
    Maps:
    10
    Spells:
    4
    Template:
    5
    Tutorials:
    6
    Resources:
    28
    Leaks aren't problem,
    1st of all code won't compile.
    2nd GroupEnum native can't pick units with locust so just remove that condition.
    3rd will be to replace ForGroup with FirstOfGroup
    4th use X,Y coordinates over location

    I don't understand what your spell do, but it seams when you learn some spell it will start timer and each 1 sec deal damage to all units around you eh?

    Well there are many other different ways how to code this, I will now post your code and below mine idea:

    Code (vJASS):
    library RainOfChaos initializer Init

        globals
            private group G1 = CreateGroup()
            private group G2 = CreateGroup()
        endglobals

        private function Iterate takes nothing returns nothing
            local unit u1
            local unit u2
            local real x
            local real y
            /* We pick all units */
            call GroupEnumUnitsInRect(G1, bj_mapInitialPlayableArea, null)
            loop
                set u1 = FirstOfGroup(G1)
                exitwhen u1 == null
                call GroupRemoveUnit(G1,u1)
           
                /* Here we check conditions 1 */
                if GetUnitState(u1, UNIT_STATE_LIFE) > 0 and GetUnitAbilityLevel(u1, 'B012') > 0 then
                    set x = GetUnitX(u1)
                    set y = GetUnitY(u1)
                    call GroupEnumUnitsInRange(G2, x, y, 600, null)
                    loop
                        set u2 = FirstOfGroup(G2)
                        exitwhen u2 == null
                        call GroupRemoveUnit(G2,u2)
                       
                        /* Here we check conditions 2 */
                        if GetUnitState(u2, UNIT_STATE_LIFE) > 0 and IsUnitEnemy(u2, GetOwningPlayer(u1)) and GetUnitAbilityLevel(u2, 'A044') > 0 then
                            call UnitDamageTarget(u2, u1, 30.00, false, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_MAGIC, null)
                            call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\NightElf\\Immolation\\ImmolationDamage.mdl", u2, "head"))
                        endif
                       
                    endloop
                endif
            endloop
        endfunction

        private function Run takes nothing returns nothing
            if GetLearnedSkill() == 'A03H' then
               call TimerStart(CreateTimer(), 1.00, true, function Iterate)
            endif
        endfunction

        private function Init takes nothing returns nothing
            local trigger trig = CreateTrigger()
            local integer i = 0
            loop
                call TriggerRegisterPlayerUnitEvent(trig, Player(i), EVENT_PLAYER_HERO_SKILL, null)
                set i = i + 1
                exitwhen i == 12
            endloop
            call TriggerAddAction(trig, function Run)
            set trig = null
        endfunction

    endlibrary


    Code (vJASS):
    library RainOfChaos initializer Init

        globals
            //Used to pick units around hero
            private group G = CreateGroup()
            //Run each 1 sec until end of time
            private timer T = CreateTimer()
            //Here we store units with skill
            private unit array U
            //How many units we stored
            private integer Counter = 0
        endglobals

        private function Iterate takes nothing returns nothing
            local unit u
            local real x
            local real y
           
            local integer i = 0
            loop
                //Loop from 0 to number of heroes we stored into array U
                exitwhen i == Counter
                set i = i + 1
                call GroupEnumUnitsInRange(G, GetUnitX(U[i]), GetUnitY(U[i]), 600, null)
                loop
                    //We pick random unit and link it with u
                    set u = FirstOfGroup(G)
                    //If there is no unit to pick from group u will equal null and both group and unit variable leak is cleaned
                    exitwhen u == null
                    //We remove unit from group so we can't pick it again
                    call GroupRemoveUnit(G,u)
                       
                    // Your shit
                    if GetUnitState(u, UNIT_STATE_LIFE) > 0 and IsUnitEnemy(u, GetOwningPlayer(U[i])) then
                        call UnitDamageTarget(U[i], u, 30.00, false, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_MAGIC, null)
                        call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\NightElf\\Immolation\\ImmolationDamage.mdl", u, "head"))
                    endif
       
                endloop
            endloop
        endfunction
       
        private function Run takes nothing returns nothing
            if GetLearnedSkill() == 'A03H' then
                //We set U[ number ] = unit
                set U[Counter] = GetTriggerUnit()
                //We increase number for example U[1] = Hero 1, U[2] = Hero 2 and so on
                set Counter = Counter + 1
                //This is cool way how to be sure to fire trigger just once, when first unit learn skill Counter will be 1 and timer will fire
                //When 2nd learn skill Counter will increase and this will be ignored until end of time :)
                if Counter == 1 then
                    call TimerStart(T, 1.00, true, function Iterate)
                endif
            endif
        endfunction

        private function Init takes nothing returns nothing
            /* Basic shit */
            local trigger trig = CreateTrigger()
            local integer i = 0
            loop
                call TriggerRegisterPlayerUnitEvent(trig, Player(i), EVENT_PLAYER_HERO_SKILL, null)
                set i = i + 1
                exitwhen i == 12
            endloop
            call TriggerAddAction(trig, function Run)
            set trig = null
        endfunction

    endlibrary
     


    As you can see mine idea is little faster, you won't pick all units on whole map each 1 sec, instead you just do loop with max number of heroes with learned skill.
    Try it it should work fine :)
     
  5. Narg666

    Narg666

    Joined:
    Aug 30, 2009
    Messages:
    112
    Resources:
    0
    Resources:
    0
    Thanks for you help, but I tested both codes, and now it lags even MORE when I'm in the middle of many units!!! I don't know what else to do!!! I'm trying to learn this, but it's hard!!! I mean, I'm not considering the spell itself, I just want to know a way to pick many units per second and do something with them without lagging too hard, in this case, I'm picking every units affected by an aura, and then looking for nearby aura sources and make the source damage the target!!

    ** EDIT **

    I almost forgot to say, it ONLY lags when I'm in the middle of MANY enemy units, and with many, I mean 20, maybe 30 or more.
    I can't just create a global variable that holds the aura source, because I want many units to have this aura, and I want them stacking!!! Also, the aura source in this case is an infernal, which can be summoned!! Don't tell me I can simply use "Permanent Immolation" ability, I'm doing this for LEARNING only, trying to find a way to create this spell.
     
  6. -Kobas-

    -Kobas-

    Joined:
    Jan 17, 2010
    Messages:
    5,892
    Resources:
    28
    Icons:
    1
    Tools:
    2
    Maps:
    10
    Spells:
    4
    Template:
    5
    Tutorials:
    6
    Resources:
    28
    Can you give me map. It makes no sense how this lags more than yours...
    Did you used first or 2nd script.
    And how many units have this spells?
     
  7. Narg666

    Narg666

    Joined:
    Aug 30, 2009
    Messages:
    112
    Resources:
    0
    Resources:
    0
    I used the first one, the ONLY modification I made was instead of using

    I used

    from IntuitiveDamageSystem.

    I tested with 4 infernals against some grunts, witch doctors and headhunters.

    ** EDIT **

    I also changed the

    to

    And the learning condition I kept mine

    Code (vJASS):


    ////////////////////////////////////////////////////////////////////////////////////////////

    private function LearnAct takes nothing returns nothing
        local timer T = CreateTimer()
        local trigger trg = CreateTrigger()
        call TimerStart(T, 1.00, true, function Actions)
       
        call TriggerAddAction(trg, function ResistanceActions)
        call TriggerAddCondition(trg, Condition(function ResistanceConditions))
        call TriggerRegisterDamageEvent(trg, 5)
       
        set T = null
        set trg = null
        call DestroyTrigger(GetTriggeringTrigger())
    endfunction

    private function LearnCond takes nothing returns boolean
        return GetLearnedSkill() == 'A03H'
    endfunction

    private function Init takes nothing returns nothing
        local trigger T = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(T, EVENT_PLAYER_HERO_SKILL)
        call TriggerAddCondition(T, Condition(function LearnCond))
        call TriggerAddAction(T, function LearnAct)
        set T = null
    endfunction

    ////////////////////////////////////////////////////////////////////////////////////////////
     


    Because it also starts a damage condition, but I have many of these and I'm pretty sure the problem is not there!! I got another units with this same ability to resist damage and it caused me no trouble.

    I'm uploading the map so you can see it for yourself, and made the changes... The triggers might be a little confused, but look for Spells category, under the Warlock comment, Rain of Chaos.

    Ignore the other heroes and the map, I'm just creating this to test my skills and learn new things.

    If I made any mistakes, please tell me!!
     

    Attached Files:

  8. -Kobas-

    -Kobas-

    Joined:
    Jan 17, 2010
    Messages:
    5,892
    Resources:
    28
    Icons:
    1
    Tools:
    2
    Maps:
    10
    Spells:
    4
    Template:
    5
    Tutorials:
    6
    Resources:
    28
    Oh you should use 2nd one, I explained below why...

    Anyway right now trigger pick unit that learn spell, this is bad, because infernals are summoned on map even before then...

    Sec will re code this fast.
     
  9. Narg666

    Narg666

    Joined:
    Aug 30, 2009
    Messages:
    112
    Resources:
    0
    Resources:
    0
    Yes, but learning the ability will activate the infernal's aura, have you tested the map? Discovered the problem???
     
  10. -Kobas-

    -Kobas-

    Joined:
    Jan 17, 2010
    Messages:
    5,892
    Resources:
    28
    Icons:
    1
    Tools:
    2
    Maps:
    10
    Spells:
    4
    Template:
    5
    Tutorials:
    6
    Resources:
    28
    Try this, it works fine for me :)
    Code (vJASS):
    library RainOfChaos initializer Init uses IntuitiveDamageSystem

        globals
            private group G      = CreateGroup()
            private group Caster = CreateGroup()
            private timer T      = CreateTimer()
        endglobals
       
        private function Iterate takes nothing returns nothing
            local unit caster = GetEnumUnit()
            local unit u
            call GroupEnumUnitsInRange(G, GetUnitX(caster), GetUnitY(caster), 600, null)
            loop
                set u = FirstOfGroup(G)
                exitwhen u == null
                call GroupRemoveUnit(G,u)
                if GetUnitState(caster, UNIT_STATE_LIFE) > 0 and GetUnitState(u, UNIT_STATE_LIFE) > 0 and IsUnitEnemy(u, GetOwningPlayer(caster)) then
                    call UnitDamageTargetEx(caster, u, 30.00, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_SPELL, false)
                    call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\NightElf\\Immolation\\ImmolationDamage.mdl", u, "head"))
                endif
            endloop
            set caster = null
        endfunction
       
        private function Run takes nothing returns nothing
            call ForGroup(Caster, function Iterate)
        endfunction
       
        private function RegisterUnit takes nothing returns nothing
            if GetUnitAbilityLevel(GetTriggerUnit(), 'A044') > 0 then
                call GroupAddUnit(Caster, GetTriggerUnit())
            endif
        endfunction
       
        private function FlushUnit takes nothing returns nothing
            if GetUnitAbilityLevel(GetTriggerUnit(), 'A044') > 0 then
                call GroupRemoveUnit(Caster, GetTriggerUnit())
            endif
        endfunction
       
        /***********************************************************************************/
        /*                               Useless code                                      */
        /*                   This below will register already created units                */
        /***********************************************************************************/
        /******/private function RemoveOnly_RegisterUnit takes nothing returns nothing/*****/
        /**********/if GetUnitAbilityLevel(GetEnumUnit(), 'A044') > 0 then/*****************/
        /**************/call GroupAddUnit(Caster, GetEnumUnit())/***************************/
        /**********/endif/******************************************************************/
        /******/endfunction/****************************************************************/
        /***********************************************************************************/
       
        private function Init takes nothing returns nothing
            local trigger trig = CreateTrigger()
            local region rectRegion = CreateRegion()
            local integer i = 0
            call RegionAddRect(rectRegion, bj_mapInitialPlayableArea)
            call TriggerRegisterEnterRegion(trig, rectRegion, null)
            call TriggerAddAction(trig, function RegisterUnit)
            set trig = CreateTrigger()
            loop
                call TriggerRegisterPlayerUnitEvent(trig, Player(i), EVENT_PLAYER_UNIT_DEATH, null)
                set i = i + 1
                exitwhen i == 12
            endloop
            call TriggerAddAction(trig, function FlushUnit)
            set trig = null
            call TimerStart(T, 1.00, true, function Run)
           
            /*
            * This below will register already created units
            */

            call ForGroupBJ( GetUnitsInRectAll(GetPlayableMapRect()), function RemoveOnly_RegisterUnit )
           
        endfunction

    endlibrary


    Ofc just remove that part of useless code.
    :)

    EDIT:

    Here is my final suggestion:
    Code (vJASS):
    library RainOfChaos initializer Init uses IntuitiveDamageSystem

        globals
            private group G      = CreateGroup()
            private group Caster = CreateGroup()
            private timer T      = CreateTimer()
           
            private boolean TurnedOff = true //Timer is disabled on start
        endglobals
       
        private function Iterate takes nothing returns nothing
            local unit caster = GetEnumUnit()
            local unit u
            call GroupEnumUnitsInRange(G, GetUnitX(caster), GetUnitY(caster), 600, null)
            loop
                set u = FirstOfGroup(G)
                exitwhen u == null
                call GroupRemoveUnit(G,u)
                if GetUnitState(caster, UNIT_STATE_LIFE) > 0 and GetUnitState(u, UNIT_STATE_LIFE) > 0 and IsUnitEnemy(u, GetOwningPlayer(caster)) then
                    call UnitDamageTargetEx(caster, u, 30.00, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_SPELL, false)
                    call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\NightElf\\Immolation\\ImmolationDamage.mdl", u, "head"))
                endif
            endloop
            set caster = null
        endfunction
       
        private function Run takes nothing returns nothing
            call ForGroup(Caster, function Iterate)
        endfunction
       
        private function RegisterUnit takes nothing returns nothing
            if GetUnitAbilityLevel(GetTriggerUnit(), 'A044') > 0 then
                call GroupAddUnit(Caster, GetTriggerUnit())
                if TurnedOff then
                    call TimerStart(T, 1.00, true, function Run)
                    set TurnedOff = false
                endif
            endif
        endfunction
       
        private function FlushUnit takes nothing returns nothing
            local unit u
            if GetUnitAbilityLevel(GetTriggerUnit(), 'A044') > 0 then
                call GroupRemoveUnit(Caster, GetTriggerUnit())
                set u = FirstOfGroup(Caster)
                if u == null then
                    set TurnedOff = true
                    call PauseTimer(T)
                endif
            endif
            set u = null
        endfunction
       
        private function Init takes nothing returns nothing
            local trigger trig = CreateTrigger()
            local region rectRegion = CreateRegion()
            local integer i = 0
            call RegionAddRect(rectRegion, bj_mapInitialPlayableArea)
            call TriggerRegisterEnterRegion(trig, rectRegion, null)
            call TriggerAddAction(trig, function RegisterUnit)
            set trig = CreateTrigger()
            loop
                call TriggerRegisterPlayerUnitEvent(trig, Player(i), EVENT_PLAYER_UNIT_DEATH, null)
                set i = i + 1
                exitwhen i == 12
            endloop
            call TriggerAddAction(trig, function FlushUnit)
            set trig = null
        endfunction

    endlibrary


    Timer will fire only when there is at least 1 alive infernal unit.
     
  11. Narg666

    Narg666

    Joined:
    Aug 30, 2009
    Messages:
    112
    Resources:
    0
    Resources:
    0
    WoW, it worked just fine!! Thank you, really!! Thank you very much for this!! I'm giving you rep+!!
     
  12. -Kobas-

    -Kobas-

    Joined:
    Jan 17, 2010
    Messages:
    5,892
    Resources:
    28
    Icons:
    1
    Tools:
    2
    Maps:
    10
    Spells:
    4
    Template:
    5
    Tutorials:
    6
    Resources:
    28
    I hope you learned more about this, I checked your other triggers, you more or less make same mistakes all around, but that's not big deal, I was like you as well.
    Try to avoid locations completely, also Red code is bad in 99 cases, only trigger register shit is good (but even this can be improved)...
    Pooled wait is big error.
    Use timer for that :)

    here is cool idea how to fix many things:
    Code (vJASS):

    globals
        private integer readInteger = 0
        private integer writeInteger = 0
       
        private unit array U
    endglobals

    function B takes nothing returns nothing
        set readInteger = readInteger + 1
        call KillUnit( U[readInteger] )
        if readInteger == writeInteger then
            set readInteger = 0
            set writeInteger = 0
        endif
        call DestroyTimer(GetExpiredTimer())
    endfunction

    function A takes nothing returns nothing
        set writeInteger = writeInteger  + 1
        set U[writeInteger] = GetTriggerUnit()
        call TimerStart(CreateTimer(), 4.00, false, function B )
    endfunction
     
     
    Last edited: Dec 7, 2012
  13. Hashjie

    Hashjie

    Joined:
    Apr 20, 2009
    Messages:
    1,515
    Resources:
    0
    Resources:
    0
    Code (vJASS):
    call TimerStart(CreateTimer(), 4.00, false, function A )


    The callback is the same function instead of B.
    That will probably cause some issues or confusions :p
     
  14. -Kobas-

    -Kobas-

    Joined:
    Jan 17, 2010
    Messages:
    5,892
    Resources:
    28
    Icons:
    1
    Tools:
    2
    Maps:
    10
    Spells:
    4
    Template:
    5
    Tutorials:
    6
    Resources:
    28
    Ye ye ye my bad ^_^
     
  15. Narg666

    Narg666

    Joined:
    Aug 30, 2009
    Messages:
    112
    Resources:
    0
    Resources:
    0
    PolledWait leaks????

    I only used the Red code sometimes for DistanceBetweenPoints, AngleBetweenPoints or PolarProjection, how can I improve this?

    This Idea of yours is to replace PolledWait?

    ** EDIT **

    Oh, and I also use red code for UnitHasItemOfTypeBJ