• 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.

[vJASS] Struct-attached Timer doesn't start

Status
Not open for further replies.
Level 4
Joined
May 25, 2009
Messages
100
I created a Cone-of-Vision-system and used hashtables for everything, but because it looked ugly and i didn't want to look up every time, which Childkey stores which Variable, i created some structs and used the Tipp PurgeandFire gave me. LINK

My Problem is now, that some Timers just don't start.
JASS:
function lis_isinsight takes nothing returns nothing
    local globaltimerstruct timerstruct = globaltimerstruct[GetExpiredTimer()]   // Get Expired Timer for the HandleId
    local globaltimerstruct newtimerstruct = globaltimerstruct.create(CreateTimer())
    local globalunitstruct unitstruct=globalunitstruct[timerstruct.COV_THISUNIT] // Create a New Timer for the Collisioncheck
    local unit stunit = timerstruct.COV_THISUNIT
    local timer t = timerstruct.THISTIMER
    local timer newt = newtimerstruct.THISTIMER
    local unit dummy        // Dummy which will check the collision
    local real heroposx = GetUnitX(hero)    //X-Coordinate of Hero
    local real heroposy = GetUnitY(hero)    //Y-Coordinate of Hero
    local real stunitposx = GetUnitX(stunit)    //X-Coordinate of unit
    local real stunitposy = GetUnitY(stunit)    //Y-Coordinate of unit
    // Distance between Hero and unit
    local real distance = SquareRoot(((stunitposx-heroposx)*(stunitposx-heroposx))+((stunitposy-heroposy)*(stunitposy-heroposy)))
    //call BJDebugMsg(I2S(GetHandleId(newt)))
   
   // If Distance between Hero and Unit is over 735 then destroy the Effect (if created) and end check
    if distance > 735 then
        call BJDebugMsg("distance to high")
        call PauseTimer(t)
        call DestroyTimer(t)
        set unitstruct.COV_TICK=0.00
        if unitstruct.COV_SPECIALEFFECTBOOL then
            call DestroyEffect(unitstruct.COV_EFFECT)
            set unitstruct.COV_SPECIALEFFECTBOOL=false
        endif
    endif
    
    //If Hero is in cone of Vision and Unit is alive
    if lis_isincone(stunit) and IsUnitAlive.evaluate(stunit) then
        // Stop current Timer and flushChild
        call PauseTimer(t)
        call DestroyTimer(t)
        
        // Create Dummy
        set dummy = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE),'e000',stunitposx,stunitposy,0)
        
        set unitstruct.COV_CROUCHBOOL=FALSE //Set Hero doesn't have to duck
        
        //Save the unit, dummy and range to new HandleID
        set newtimerstruct.COV_THISUNIT=stunit
        set newtimerstruct.COV_DUMMYUNIT=dummy
        set unitstruct.COV_RANGE=0
        call newtimerstruct.save()
        // Start Timer
        call BJDebugMsg(I2S(GetHandleId(newtimerstruct.THISTIMER)))
        call TimerStart(newtimerstruct.THISTIMER, 0.01, true, function lis_collisioncheck)
        call BJDebugMsg(I2S(GetHandleId(newt)))
    // If not in Cone of Vision Destroy Effect (If created)
    else 
        call DestroyTimer(newt)
        set unitstruct.COV_TICK=0.0
        if unitstruct.COV_SPECIALEFFECTBOOL then
            call DestroyEffect(unitstruct.COV_EFFECT)
            set unitstruct.COV_SPECIALEFFECTBOOL=false
        endif
    endif
    
    //Save Struct
    call unitstruct.save()
    
    //Remove Leaks
    call unitstruct.destroy()
    call timerstruct.destroy()
    call newtimerstruct.destroy()
    set t=null
    set stunit=null
    set newt=null
    set dummy=null
endfunction


//Start Timer and ini the booleans, units etc.
function Trig_stealthini_Actions takes nothing returns nothing
    local globaltimerstruct timerstruct = globaltimerstruct.create(CreateTimer())
    local globalunitstruct unitstruct=globalunitstruct[GetEnteringUnit()]
    set unitstruct.COV_SPOTTEDBOOL=FALSE
    set unitstruct.COV_SPECIALEFFECTBOOL=FALSE
    set unitstruct.COV_TICK=0.00
    set timerstruct.COV_THISUNIT=GetEnteringUnit()
    call unitstruct.save()
    call timerstruct.save()
    call TimerStart(timerstruct.THISTIMER, 0.1, true, function lis_isinsight)
    call timerstruct.destroy()
    call unitstruct.destroy()
endfunction

//===========================================================================
function InitTrig_Lineinsight takes nothing returns nothing
    set hero = gg_unit_h000_0000 //Ini the local Herovariable
    set gg_trg_Lineinsight = CreateTrigger(  )
    call TriggerRegisterUnitInRange( gg_trg_Lineinsight, hero, 700.00,null )
    call TriggerAddAction( gg_trg_Lineinsight, function Trig_stealthini_Actions )
endfunction


The Problem is, that the timer "newt" doesn't start in the function "lis_isinsight". I get both DebugMsg (The HandleIDs are the same).
It doesn't matter whats in function "lis_collisioncheck"...Even if it's just one "call BJDebugMsg("test")" i don't get it.
And the strange thing is, that the timer "t" in "Trig_stealthini_Actions" starts the function "lis_isinsight" without problems...and there is not a big difference between these two timers, is there?


JASS:
///////////////////////////////////////////////////////////////////////////////////
//////////Unit Struct for the COV-System //////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////

struct globalunitstruct
    unit THISUNIT   //Unit the Structs belongs to
    unit PARTNERUNIT    //The Partnerunit
    unit CONTROLDUMMY   //Controldummy for Player 2 Units only
    real COV_TICK=0     //Tick for the ConeOfVision-system (Player 2 Units only)
    real COV_RANGE=0    //Range for Dummymove in the COV-system (Player 2 Units only)
    boolean COV_SPOTTEDBOOL=false   //Bool if Unit spotted Hero (Player 2 Units only)
    boolean COV_SPECIALEFFECTBOOL=false     //Bool if overhead Unit is a Effect (Player 2 Units only)
    boolean COV_CROUCHBOOL=false    //Bool if Hero has to Duck (Player 2 Units only)
    effect COV_EFFECT       //Overhead Effect for Thisunit (Player 2 Units only)
    
    //Create-method which saves directly the THISUNIT
    static method create takes unit u returns thistype 
        local globalunitstruct newstruct = globalunitstruct.allocate()
        set newstruct.THISUNIT = u
        return newstruct
    endmethod

    
    //Method to Save Struct to THISUNIT in hashtable
    method save takes nothing returns nothing
        call SaveInteger(udg_hashtable,GetHandleId(this.THISUNIT),0,this)
    endmethod
    
    //Method to Load Struct of THISUNIT in hashtable
    static method operator [] takes unit u returns thistype
        return LoadInteger(udg_hashtable,GetHandleId(u), 0 )
    endmethod
endstruct
//---------------------------------------------------------------------------------

JASS:
///////////////////////////////////////////////////////////////////////////////////
//////////Timer Struct for the COV-System and the Clickables-system////////////////
///////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////

struct globaltimerstruct
    timer THISTIMER     //Timer the struct belongs to
    unit COV_THISUNIT   //Unit for the COV-System which schould be passed to timerfunction
    unit COV_DUMMYUNIT  //Dummyunit for the COV-System which schould be passed to timerfunction
    
    //Create and set THISTIMER to the timer
    static method create takes timer t returns thistype
        local globaltimerstruct newstruct = globaltimerstruct.allocate()
        set newstruct.THISTIMER=t
        return newstruct
    endmethod
    
    //Method to Save Struct to THISTIMER in hashtable
    method save takes nothing returns nothing
        call SaveInteger(udg_hashtable,GetHandleId(this.THISTIMER),0,this)
    endmethod
    
    //Method to Load Struct of THISTIMER in hashtable
    static method operator [] takes timer t returns thistype
        return LoadInteger(udg_hashtable, GetHandleId(t), 0)
    endmethod
    
endstruct
//---------------------------------------------------------------------------------


Maybe i just missed something really obvious and my brain is just to tired.
I hope you can help me :D
thx in advance!

PS: I don't have to create a new globalunitstruct in "Trig_stealthini_Actions" 'cause they are already created before for every unit ...but i think that the whole globalunitstruct is not the problem anyway, but the globaltimerstruct.

PSS: I know that the code is not 100% optimized
 
Level 17
Joined
Feb 11, 2011
Messages
1,860
I didn't read through all the code, because I'm too lazy :p
Have you looked at TimerUtils (or something silimar)? Or am I misunderstanding what you are wanting?
It allows you to 'attach' an integer to a timer, which is great for attaching struct instances. Example:

JASS:
local timer t = NewTimerEx(this) // attach this instance to timer.
call TimerStart(t, 1.0, false, function thistype.onExpire) // start timer.

The onExpire method:

JASS:
local thistype this = GetTimerData(GetExpiredTimer()) // load timer's data.
call ReleaseTimer(GetExpiredTimer()) // release it.
// do stuff
 
Level 4
Joined
May 25, 2009
Messages
100
The saving of structs is working fine.
As is said: The first timer starts correctly. It's just the secondtimer which isn't working.

And i don't want to use so many snippets and TimerUtils uses SaveInteger() to save structs as well, so there is no real differents between my system and TimerUtils
 
Level 8
Joined
Feb 3, 2013
Messages
277
Your structs are hella confusing; sorry but could you explain what this is supposed to do again?

The saving of structs is working fine.
As is said: The first timer starts correctly. It's just the secondtimer which isn't working.

And i don't want to use so many snippets and TimerUtils uses SaveInteger() to save structs as well, so there is no real differents between my system and TimerUtils
Lol, if its the same thing and TimerUtils is better, why not use TU.
 
Level 4
Joined
May 25, 2009
Messages
100
msongyboi said:
Your structs are hella confusing; sorry but could you explain what this is supposed to do again?

For the Timerstruct:
I want to save variables for different timers, so that if i have a timer that i can acces custom variables, like ".COV_SPOTTEDBOOL" (needed for my COV-system).
The only important variable so far is ".THISTIMER" which is the timer the struct belongs to.
The create()-method is a normal create method, just that it saves the timer, which the struct belongs to direktly to the .THISTIMER-var.
The save()-method just saves the struct to ".THISTIMER" in a hashtable and the []-method loads the struct.
So bevor i start a timer i save() the struct to the timer, start the timer and in the timer-funtion i can load the struct again and have access to all my customvars.

The Unitstruct is basicly the same, just for units instead of timers.

msongyboi said:
Lol, if its the same thing and TimerUtils is better, why not use TU.
Why should i? I'm still learning vjass and don't want to use custom snippets everytime i have a problem.
And the first timer with all his attached structs is working, just not the second one...so i don't think that some timersnippets will solve the problem.
 
I think I see what is happening. This is probably the culprit:
JASS:
    call unitstruct.save()
    call timerstruct.save()
    call TimerStart(timerstruct.THISTIMER, 0.1, true, function lis_isinsight)
    call timerstruct.destroy()
    call unitstruct.destroy()
You are destroying them right after you start the timer. Why? Remember that you are still using the struct information. :) If you destroy it, it will be deallocated. This means that the instance will be freed, and thus the "newtimerstruct" takes up the same instance as "timerstruct" (since that instance is freed), so they point to the same timer and you end up destroying it before you start it.

Basically, with structs you should only destroy them when you are done using that specific instance. Usually this is at the end of the spell. In this case, your spell still has actions to go, and you use it in the timer callback, so you shouldn't destroy it just yet.

So as you can see here:
JASS:
    //Remove Leaks
    call unitstruct.destroy()
    call timerstruct.destroy()
    call newtimerstruct.destroy()
You aren't actually clearing leaks. You are just freeing the instance so it can be used by other things. But you don't actually want that to happen right away, in this case. You are still using that info. It is like giving someone a box of video games when you still want to play the games in it. Instead, you should give it away after you are done playing them. ;)

Here is an example of how a simple spell would look using your system:
JASS:
scope Example initializer onInit
    // 'A000' will deal 100 damage every second until the target dies

    private function onExpire takes nothing returns nothing
        local globaltimerstruct t = globaltimerstruct[GetExpiredTimer()]
        call UnitDamageTarget(t.COV_THISUNIT, t.COV_DUMMYUNIT, 100, true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, null)
        if GetWidgetLife(t.COV_DUMMYUNIT) < 0.405 then // is the unit dead?
            call PauseTimer(t.THISTIMER)
            call DestroyTimer(t.THISTIMER)
            call t.destroy() // destroy it now that i no longer need the data with this
        endif
        // if he isn't dead, then just continue
    endfunction

    private function onSpell takes nothing returns nothing
        local globaltimerstruct t 
        if GetSpellAbilityId() == 'A000' then
            set t = globaltimerstruct.create()
            set t.COV_THISUNIT = GetTriggerUnit() // assign some variables
            set t.COV_DUMMYUNIT = GetSpellTargetUnit()
            call t.save() // save
            call TimerStart(t.THISTIMER, 1., true, function onExpire) // start timer
        endif
        return false
    endfunction

    private function onInit takes nothing returns nothing
        local trigger t = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
        call TriggerAddCondition(t, Condition(function onSpell))
    endfunction
endscope

Now, this is just an example. It won't do what you want. However, this example will show you when you should actually destroy the instance.
 
Level 4
Joined
May 25, 2009
Messages
100
And again....PurgeandFire xD
You're right: I was destroying structs i still used.
I just thought, that if i save() a struct it would create a new instance in the hashtable of this struct and i could destroy the old one. The same for the load()-method...that it would create a new instance in my variable from the hashtable.
But i was wrong...
Thanks :D

Edit: Sry, can't give you rep again.
 
Status
Not open for further replies.
Top