• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

Trigger Spell Optimization (no! priority the speed)

Status
Not open for further replies.
Level 17
Joined
Nov 13, 2006
Messages
1,814
1st of all, i want say for me the speed important and not really the accurated delays/wait between actions

Info:
-Alot seperated spell trigger
-They arent different kind (dot, spamable heal over time, missile ability like firebolt, buff like add x=1 and after y second x=0[group or just 1 unit buffs])
-every case exclude missle spells, i used a TSA with a loop and till duration end i checked if unit died/caster died or no, if yes then exit from loop, destroy special effect on caster or target and change a variable value/or just stop the dot/heal
-few case i used unit group, few case just 1 target unit


all got condition like this:
JASS:
function Trig_Dotw_Conditions takes nothing returns boolean
    return GetSpellAbilityId() == 'A02L'
endfunction

then action, but i got a advice to use only condition and in condition i can use if and return allways false but my question is, if i must declare alot thing like
JASS:
    local unit uc = GetTriggerUnit()
    local unit u = GetSpellTargetUnit()
    local unit u1 
    local unit u2 
    local unit u3 
    local unit u4 
    local unit u5 
    local integer a = 0
    local integer h1 = 330
    local integer h2 = 320
    local integer d = 10
    local real x = GetUnitX(u)
    local real y = GetUnitY(u)
    local real g = (3.14159/180)
    local real x1 = x + 300 * Cos(g * 0)         
    local real y1 = y + 300 * Sin(g * 0)
    local real x2 = x + 300 * Cos(g * 72)         
    local real y2 = y + 300 * Sin(g * 72)
    local real x3 = x + 300 * Cos(g * 144)         
    local real y3 = y + 300 * Sin(g * 144)
    local real x4 = x + 300 * Cos(g * 216)         
    local real y4 = y + 300 * Sin(g * 216)
    local real x5 = x + 300 * Cos(g * 288)         
    local real y5 = y + 300 * Sin(g * 288)
    local real sp = 100
    local real lhp = GetUnitAbilityLevel(uc, 'A02S')*5+10
    local real hp = GetWidgetLife(u)
    local real chp = hp
    local real cchp = GetWidgetLife(uc)
    local real mhp = hp/lhp
    local lightning l1 
    local lightning l2 
    local lightning l3 
    local lightning l4
    local lightning l5 
    local lightning l6 
    local lightning l7 
    local lightning l8 
    local lightning l9
    local lightning l10 
    local player p = GetTriggerPlayer()
    local string s1 = udg_Effects[5]
    local effect f =  AddSpecialEffectTarget(s1, u, "origin")

and in few ability case just
JASS:
local unit pu
local unit u = GetTriggerUnit()
local player p = GetTriggerPlayer()
local real xt = GetSpellTargetX()
local real yt = GetSpellTargetY()
local real dmg = GetUnitAbilityLevel(u, 'A03A') *  GetHeroLevel(u) + udg_TotalSpellPower[GetPlayerId(p)+1]/5
local real hdmg = dmg/2
local string array s
local effect f 
local group gr = bj_lastCreatedGroup

so if i wanna merge every ability to 1 single trigger then everytime maybe i must declare useless locals (because example few ability is no target ability, few single target, few aoe target also few got 1 effect another 10 etc)

local declaretions slowdown something, or better the useing the separated triggers for each spell 1 triggers coz difference in speed is similiar than merge but declare all variable even its not needed?

Another thing, if i make a single periodic trigger and for each spell make unit group and with if i check what spell then check every unit group in periodic trigger is better than use TSA with loop in each trigger spell in faster trigger view?

i use sometime loop only for this

JASS:
loop
exitwhen (a==bdur)
call TriggerSleepAction(1)
  loop
   exitwhen (i==d)
      if IsUnitType(ua[i], UNIT_TYPE_DEAD) then
       call DestroyEffect(df[i])
       set e = LoadInteger(udg_Buff_Table, 3, GetUnitUserData(ua[i]))
       call SaveInteger( udg_Buff_Table, 3, GetUnitUserData(ua[i]), e - rate )
       set df[i] = null
       set ua[i] = null
      endif
       set i = i + 1
  endloop
set i = 0
set a = a + 1
endloop
single unit version
JASS:
loop
  exitwhen IsUnitType(u, UNIT_TYPE_DEAD) or i==dur
  call TriggerSleepAction(1) 
  set i = i + 1
endloop
 
Last edited:
Level 17
Joined
Nov 13, 2006
Messages
1,814

ok but atleast u can tell this amount of trigger with ability cast event make a visible slowdown or dont really noticeable?

problem is i use wait, in most of trigger
Don't use TriggerSleepAction inside registered code.

updated the 1st post about solution for replace TSA where i use tsa only for check unit die/or duration expire

example for a missle system need a 0.03 periodic timer atleast for unit alive checks atleast 1sec, where have balance in speed between the useing periodic triggers with unit group and useing TSA loop?

another question, how faster if i use specific unit event instead generic unit event(or its not comparable with Bribe system)?
(i think here i can add to every spell trigger event at begining of game when i check if user control user/is playing then add event to spells)
 
Level 17
Joined
Nov 13, 2006
Messages
1,814
Bump

somebody can give asnwer to this?


i want replace the TSA to timer, i mean i want make only 1 periodic trigger what run every 1 sec, atm i have around 6-8 trigger where if simplify its do like this:

-if x ability casted, then:
-save in hashtable a value (key:custom value/buff id[i indexed my trigger buffs])
-add special effect to target
-loop till duration end or target die
-when exited from loop then destroy attachment and save 0 to harshtable (i use this for increase critical rate etc)

so i want do something like this:
-if spell casted then add unit to caster unit group
-save to 1 harshtable (buff id or buffs id, units, duration,(effetc or how could i make it without too much effect array?))
-periodic trigger decrease everysec duration and update in harshtable
-if over then with a if (depend by buff id) change number/numbers in hashtable for 1 or more unit/destroy special effect

i can do without problem if we talk about 1 aoe buff type, so add to caster group everybuffer, save to hashtable, then change in periodic trigger but how can i do for more buff/spell what different without makeing unit group for each trigger buff and hashtable for each trigger buff?

possible?

(since i also must make hashtables for single target abilities like firebolt etc, another for peridic things like dots/heal and another for shorter things like arrow rain etc if each spell need hashtable then horrible amount checking and hashtable/variable)

how could i reduce?
 
Level 17
Joined
Nov 13, 2006
Messages
1,814
atm i use gui but i use but i am out of ideea in jass too (still not new gen :p)
  • Timer
    • Events
      • Time - Every 1.00 seconds of game time
    • Conditions
    • Actions
      • Unit Group - Pick every unit in Buff_AttLvBuff and do (Actions)
        • Loop - Actions
          • Set cv = (Custom value of (Picked unit))
          • Set Timer_AttLv[cv] = (Timer_AttLv[cv] - 1)
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • Timer_AttLv[cv] Equal to 0
            • Then - Actions
              • Hashtable - Save ((Load 10 of cv from Buff_Table) - Buff_AttLvVal[cv]) as 10 of cv in Buff_Table
            • Else - Actions
      • Unit Group - Pick every unit in Buff_DefLvBuff and do (Actions)
        • Loop - Actions
          • Set cv = (Custom value of (Picked unit))
          • Set Timer_DefLv[cv] = (Timer_DefLv[cv] - 1)
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • Timer_DefLv[cv] Equal to 0
            • Then - Actions
              • Hashtable - Save ((Load 11 of cv from Buff_Table) - Buff_DefLvVal[cv]) as 11 of cv in Buff_Table
            • Else - Actions
      • Unit Group - Pick every unit in Buff_PdefBuff and do (Actions)
        • Loop - Actions
          • Set cv = (Custom value of (Picked unit))
          • Set Timer_Pdef[cv] = (Timer_Pdef[cv] - 1)
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • Timer_Pdef[cv] Equal to 0
            • Then - Actions
              • Hashtable - Save ((Load 12 of cv from Buff_Table) - Buff_PdefVal[cv]) as 12 of cv in Buff_Table
            • Else - Actions
      • Unit Group - Pick every unit in Buff_MdefBuff and do (Actions)
        • Loop - Actions
          • Set cv = (Custom value of (Picked unit))
          • Set Timer_Mdef[cv] = (Timer_Mdef[cv] - 1)
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • Timer_Mdef[cv] Equal to 0
            • Then - Actions
              • Hashtable - Save ((Load 13 of cv from Buff_Table) - Buff_MdefVal[cv]) as 13 of cv in Buff_Table
            • Else - Actions
      • Unit Group - Pick every unit in Buff_CritDmgBuff and do (Actions)
        • Loop - Actions
          • Set cv = (Custom value of (Picked unit))
          • Set Timer_CritDmg[cv] = (Timer_CritDmg[cv] - 1)
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • Timer_CritDmg[cv] Equal to 0
            • Then - Actions
              • Hashtable - Save ((Load 2 of cv from Buff_Table) - Buff_CritDmgVal[cv]) as 2 of cv in Buff_Table
            • Else - Actions
      • Unit Group - Pick every unit in Buff_CritBuff and do (Actions)
        • Loop - Actions
          • Set cv = (Custom value of (Picked unit))
          • Set Timer_Crit[cv] = (Timer_Crit[cv] - 1)
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • Timer_Crit[cv] Equal to 0
            • Then - Actions
              • Hashtable - Save ((Load 1 of cv from Buff_Table) - Buff_CritVal[cv]) as 1 of cv in Buff_Table
            • Else - Actions
      • Unit Group - Pick every unit in Buff_RefBuff and do (Actions)
        • Loop - Actions
          • Set cv = (Custom value of (Picked unit))
          • Set Timer_Ref[cv] = (Timer_Ref[cv] - 1)
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • Timer_Ref[cv] Equal to 0
            • Then - Actions
              • Hashtable - Save ((Load 3 of cv from Buff_Table) - Buff_RefVal[cv]) as 3 of cv in Buff_Table
            • Else - Actions
      • Unit Group - Pick every unit in Buff_HpBuff and do (Actions)
        • Loop - Actions
          • Set cv = (Custom value of (Picked unit))
          • Unit Group - Pick every unit in HpBuffs[cv] and do (Actions)
            • Loop - Actions
              • Set cv1 = (Custom value of (Picked unit))
              • Set Timer_HP_Buff[cv1] = (Timer_HP_Buff[cv1] - 1)
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • Timer_HP_Buff[cv1] Equal to 0
                • Then - Actions
                  • Set A = (Load 8 of cv1 from Buff_Table)
                  • Set unit = (Picked unit)
                  • Custom script: call AddHPMP(true, udg_A*-1, udg_unit)
                • Else - Actions
      • Unit Group - Pick every unit in Buff_HpRegenBuff and do (Actions)
        • Loop - Actions
          • Set cv = (Custom value of (Picked unit))
          • Unit Group - Pick every unit in HpRegenBuffs[cv] and do (Actions)
            • Loop - Actions
              • Set cv1 = (Custom value of (Picked unit))
              • Set Timer_HPRegen_Buff[cv1] = (Timer_HPRegen_Buff[cv1] - 1)
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • Timer_HPRegen_Buff[cv1] Equal to 0
                • Then - Actions
              • Hashtable - Save ((Load 3 of cv1 from Buff_Table) - Buff_HPRegenVal[cv1]) as 3 of cv in Buff_Table
                • Else - Actions
      • Unit Group - Pick every unit in Buff_MpRegenBuff and do (Actions)
        • Loop - Actions
          • Set cv = (Custom value of (Picked unit))
          • Unit Group - Pick every unit in MpRegenBuffs[cv] and do (Actions)
            • Loop - Actions
              • Set cv1 = (Custom value of (Picked unit))
              • Set Timer_MPRegen_Buff[cv1] = (Timer_MPRegen_Buff[cv1] - 1)
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • Timer_MPRegen_Buff[cv1] Equal to 0
                • Then - Actions
              • Hashtable - Save ((Load 4 of cv1 from Buff_Table) - Buff_MPRegenVal[cv1]) as 4 of cv in Buff_Table
                • Else - Actions
and ofc still not over since it was only 1/3 buff :/ so any ideea?

coz slowly i doubt this way is faster than with simple TSA and save integer to hash, also this way each buff need 1 unit group, 1 unit group array, 2 integer array, and create d& destroy group since cant be 1000+++++ unit group in map without higher ram usage (i think)
 
Level 14
Joined
Apr 20, 2009
Messages
1,543
Why not create 1 unit group, then add all units to that unit group and give them more custom values to separate the units inside the unit group.

This way you only have to enumerate all the units inside the group once instead of .... times.
You then seperate them through their custom values.

If you set a local variable to be the group, create the group, use the group and then destroy it in the same trigger, then this would probably be the most optimized way of doing it.

If this is impossible because the units get added and removed respectively, then simply use a global variable and don't destroy the group.
It's not considered to be a leak if it's supposed to be there the entire game.

Be sure that you remove a unit from the group if it's not being needed anymore ofcourse...

since cant be 1000+++++ unit group in map without higher ram usage (i think)
(The maximum for arrays, and lots of other stuff such as map size inside warcraft 3 is 8192 b.t.w. :wink:)
 
Level 17
Joined
Nov 13, 2006
Messages
1,814
Why not create 1 unit group, then add all units to that unit group and give them more custom values to separate the units inside the unit group.

This way you only have to enumerate all the units once instead of .... times.

If you set a local variable to be the group, create the group, use the group and then destroy it in the same trigger, then this would probably be the most optimized way of doing it.

If this is impossible because the units get added and removed respectively, then simply use a global variable and don't destroy the group.
It's not considered to be a leak if it's supposed to be there the entire game.

Be sure that you remove a unit from the group if it's not being needed anymore ofcourse...
(The maximum for arrays, and lots of other stuff such as map size inside warcraft 3 is 8192 b.t.w. not 1000+++++ :wink:)

if i give cutom value then its screw up the indexer
another thing i cant add unit to 1 single unit group since example if he have 2 buff then in unit group cant be 2x same unit :/

ok i understand 1000++ still not 8000 but if we see that much pick all (i got ~20 buff and from this half aoe, so again another unit group array), add/remove, calculate, save load harshtable could be laggy no?

lets say just 1 buff... the hp buff, ok maximum 10 player have on map, lets say all do hp buff , each buff another 9 unit too so overall 100 buff check each second only for hp buff, but pdef, mdef, crit,hpregen,mpregen,reflect etc

So in max case 1000-2000 chech cv, pick all, check cv, pick all loop and decrease timer etc

every buff exclude unit group(most hated since unitgroups are array and index is custom value of unit, i must create each time unit group [udg_HpBuffs[udg_cv]=CreateGroup()] and destory it at end) get another ~3 integer/real array for keep the target buff like amount, timer etc (ok i think its not problem but after alot got value since the 0 is value too :/)

overall somebody can tell me if i do that much variable and check every sec then its slowdown
 
Level 14
Joined
Apr 20, 2009
Messages
1,543
if i give cutom value then its screw up the indexer

Why not use a seperate indexer?

another thing i cant add unit to 1 single unit group since example if he have 2 buff then in unit group cant be 2x same unit :/

No but changing the custom value gives you the ability to check if the unit has 2 buffs...

ok i understand 1000++ still not 8000 but if we see that much pick all (i got ~20 buff and from this half aoe, so again another unit group array), add/remove, calculate, save load harshtable could be laggy no?

lets say just 1 buff... the hp buff, ok maximum 10 player have on map, lets say all do hp buff , each buff another 9 unit too so overall 100 buff check each second only for hp buff, but pdef, mdef, crit,hpregen,mpregen,reflect etc

So in max case 1000-2000 chech cv, pick all, check cv, pick all loop and decrease timer etc

I was just telling you the maximum that the game can handle before it crashes. And yes, it does make everything really slow and laggy the way it is right now >.>

every buff exclude unit group(most hated since unitgroups are array and index is custom value of unit, i must create each time unit group [udg_HpBuffs[udg_cv]=CreateGroup()] and destory it at end) get another ~3 integer/real array for keep the target buff like amount, timer etc (ok i think its not problem but after alot got value since the 0 is value too :/)

You don't nessecarely have to create and remove the group inside the trigger if the group is global and going to be used throughout the entire game.

overall somebody can tell me if i do that much variable and check every sec then its slowdown

You won't see the difference, checking variables is fast since it's just a pointer to the actual data inside the memory.
By checking a variable you directly get that data from the memory, instead of executing functions in order to return the data.

Grouping units together excessively does slow down a lot since your then executing a function that returns the data from the memory. Instead of directly getting the data.

Remember: you're creating a group which has to loop through every single unit it contains and it needs to execute actions for each unit that it loops through untill all units have been looped through.

Right now you're doing this every 1 second for 13 unit groups, yes that will definitly be slow...


Basically what do you think is faster:
Creating 13 unit groups that adds units to those groups through conditions and then loops through each unit inside the group in order to execute actions for each unit inside the group every 1 second of game time.
And after the units are being added and the actions are being executed for each specific unit it removes the unit from the unit group.

Or:
Create 1 unit variable with an array.
Then use an indexing system to add the units that you need to be checked to the variable.
And of course remove the units if you don't need them inside the "fake" group anymore.
Then loop through that index to get the units directly from the memory.
You can then check for each unit if the custom value that's assigned to that unit is a specific number.
Which you can then use to put them into non-existing groups by using conditions. Each if block can then seperate the units from each other.

Remember the part where I said 8192 is the maximum? You can't have more then 8192 indexes of an array, so be carefull your not exceeding this amount of units in your "fake" group.

I hope you understand where I'm going with this ;)

EDIT: check your PM
 
Last edited:
Status
Not open for further replies.
Top