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

Timers and Waits

Status
Not open for further replies.
Level 2
Joined
Mar 26, 2018
Messages
7
Hello Hive

I'm struggling to choose timer or wait to implement my solution. I have gone through the forum and read mixed claims about both of them. That they can cause desync themselves(which i doubt), one is more accurate than other and opposite. I don't want to choose one without consideration and wait for my map to fail during play. I would appreciate if anyone could make this clear to me.

What are my requirements?
They must work inside loop to pause the code for 1 second with at least 25% accuracy
No desync and leaks
 
Neither one causes a desync if used properly. I pretty much always try to use timers for a few reasons.
  • Waits send a packet over the network each time they are called. The more waits your map uses the more network traffic it will use.
  • Waits are inaccurate in multiplayer.
  • Waits are unable to pause for less than the latency of the match making low frequency operations impossible.
  • Waits are partially responsible for weird behavior like the handle stack corruption bug.
Unfortunately with timers you are forced to create a new function (trigger/action in GUI) which separates the data from your local scope. This isn't really a problem if you are using GUI without any locals but it's still less convenient than Waits. Because of this timers do not work inside of loops, instead you will have to learn how to use periodic timers.
 
Level 2
Joined
Mar 26, 2018
Messages
7
^+1 to everything TH said.

What are you trying to implement? We might be able to give you an example that'll work to your needs. Timers are a little tough to get started with, but they are really worth it. Here is a guide if you'd like it:
Visualize: Dynamic Indexing

I'm trying to create a periodical (reinforce) trigger which checks state of specific units and if they have less than max HP, then creates request for manpower from players cities, waits specific amount of time from 3 to 15 seconds depending on technology


This is city class, it has its own trigger to update state
JASS:
struct City extends array [1024]
    static integer TotalCities = 0
    static integer MaxIndex = 0
    integer id
    boolean exists
    boolean is_occupied
 
    integer real_owner
    integer owner
    real ground_pop_modifier // extra growth depends on tiles
 
    integer city_level
    real city_level_growth_modifier
 
    unit ucity
 
    integer population
    integer educated // from population
 
    // both from population
    integer free_workers // available - depends on law ( mod)
    integer used_workers // used in any way
    integer total_workers // how many in total
 
    // same principe
    integer free_manpower
    integer used_manpower
    integer total_manpower
 
    // Buildings
    boolean has_granary
    unit ugranary
 
    boolean has_barracks
    unit ubarracks
 
    boolean has_market
    unit umarket
 
    boolean has_university
    unit uuniversity
 
    boolean has_bunker
    unit ubunker
 
    //and more... + many methods
 
   endstruct

This is class for units which im working with
JASS:
struct CombatUnit extends array [3144]
    static integer TotalUnits = 0
    static integer MaxIndex = 0
 
    boolean exists
    unit uunit
    integer owner
    real reinforces_on_way
 
    //+ methods

endstruct

This is the Trigger i'm working on
JASS:
function Trig_globalV2_Actions takes nothing returns nothing
 
     
local integer i = 0
local integer unitcount = 0
local integer array reinforces
local integer requests_count = 0
// search for losses - CombatUnit
    loop
        exitwhen unitcount >= CombatUnit.TotalUnits or i >= 2048
     
        if GetUnitState(CombatUnit[i].uunit, UNIT_STATE_LIFE) > 0 then
            set unitcount = unitcount + 1
         
            if GetUnitState(CombatUnit[i].uunit,UNIT_STATE_LIFE) + CombatUnit[i].reinforces_on_way < I2R(BlzGetUnitMaxHP(CombatUnit[i].uunit)) then
             
                set requests_count = requests_count + 1
                set reinforces[i] = BlzGetUnitMaxHP(CombatUnit[i].uunit) - R2I(GetUnitState(CombatUnit[i].uunit,UNIT_STATE_LIFE)) - CombatUnit[i].reinforces_on_way
                set CombatUnit[i].reinforces_on_way = BlzGetUnitMaxHP(CombatUnit[i].uunit) - R2I(GetUnitState(CombatUnit[i].uunit,UNIT_STATE_LIFE))
             
            endif
     
        endif
        set i = i + 1
    endloop
 
 
    set i = 0
    set unitcount = 0
 
    // problem - is timer or wait more appropriate for this?
    // loop max 15 times
    // wait 1 second every iteration
    // loop through requests and check if reinforce rate (in seconds) of player is lower or equals total elapsed time
    // if yes try to request reinforces > increase HP else do nothing
    // remove request
    // continue until there are no requests left or iterated 15 times

   // this trigger runs every second so im using globals to make sure there are not multiple requests for
   // same amount of losses for unit
 
endfunction
//===========================================================================
function InitTrig_globalV2 takes nothing returns nothing
    set gg_trg_globalV2 = CreateTrigger(  )
    call TriggerRegisterTimerEventPeriodic( gg_trg_globalV2, 1.00 )
    call TriggerAddAction( gg_trg_globalV2, function Trig_globalV2_Actions )
endfunction

And this is the manpower request function
JASS:
function reinforces_requesst_manpower takes unit u, integer needed_mp, integer iplayer returns boolean
local boolean fulfilled = false   
local integer icity = 0
local integer city_count = 0
local integer array temp_mp
local integer collected_mp = 0
local integer temp = 0
local integer i = 0
    loop
     
        if City[icity].exists and City[i].owner == iplayer then
            set city_count = city_count + 1
         
            if City[icity].free_manpower > 0 then
         
                if City[icity].free_manpower > needed_mp - collected_mp - 1 then
                 
                    set temp = needed_mp - collected_mp
                    set collected_mp = collected_mp + temp
                 
                    //take mp from cities           
                    set City[icity].total_manpower = City[icity].total_manpower - temp
                    set City[icity].free_manpower = City[icity].free_manpower - temp
                    set City[icity].used_manpower = City[icity].used_manpower + temp
             
                    set temp_mp[icity] = temp
                    set temp = 0
                 
                else
             
                    set temp = City[iplayer].free_manpower
                    set collected_mp = collected_mp + temp
             
                    //take mp from cities
                    set City[icity].total_manpower = City[icity].total_manpower - temp
                    set City[icity].free_manpower = City[icity].free_manpower - temp
                    set City[icity].used_manpower = City[icity].used_manpower + temp
             
                    set temp_mp[icity] = temp
                    set temp = 0
             
         
                endif
     
            endif
         
        endif
     
        set icity = icity + 1
        exitwhen icity > 255 or city_count >= PlayerData[iplayer].total_cities or collected_mp >= needed_mp
    endloop
 
 
    set u = null
 
    if collected_mp >= needed_mp then
        return true
 
    else
 
        set city_count = 0
        loop
         
            if temp_mp[i] > 0 then
                set city_count = city_count + 1
            endif
     
                    set City[i].total_manpower = City[i].total_manpower + temp_mp[i]
                    set City[i].free_manpower = City[i].free_manpower + temp_mp[i]
                    set City[i].used_manpower = City[i].used_manpower - temp_mp[i]
             
            set i = i + 1
            exitwhen i > 1024 or city_count >= PlayerData[iplayer].total_cities
        endloop
 
        return false
    endif
endfunction

I also thought about using Damage Detection System but i would'nt need that for anything escept this

I'm sorry if i made any mistake in grammar or spelling, english is not my first language
 
Last edited:
Level 2
Joined
Mar 26, 2018
Messages
7
I have found different and more efficient solution without the need of timers and waits for my problem.
Please terminate this thread
 
Status
Not open for further replies.
Top