HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

TimedHandles

04-13-2009, 02:29 AM#1
TriggerHappy
Use this to destroy a handle after X amount of seconds.

TimerUtils is optional.

Collapse JASS:
library TimedHandles uses optional TimerUtils
/**************************************************************
*
*   v1.0.4 by TriggerHappy
*
*   Use this to destroy a handle after X amount seconds.
*
*   It's very useful for things like effects where you may
*   want it to stay in the map for a little, but not worry
*   about the cleaning memory leak. By default it supports
*   effects, lightning, weathereffect, items, ubersplats, and units.
*
*   If you want to add your own handle types copy a textmacro line
*   at the bottom and add whichever handle you want along with it's destructor.
*
*   For example:
*       //! runtextmacro TIMEDHANDLES("handle", "DestroyHandle")
*
*   Installation:
*       1. Copy this script and over to your map inside a blank trigger.
*       2. If you want more efficiency copy TimerUtils over as well.
*
*   API:
*       call DestroyEffectTimed(AddSpecialEffect("effect.mdx", 0, 0), 5)
*       call DestroyLightningTimed(AddLightning("CLPB", true, 0, 0, 100, 100), 5)
*
*   Credits to Vexorian for TimerUtils and his help on the script.
*
**************************************************************/
        
    globals
        // Check if the handle is null before destroying it
        private constant boolean NULL_SAFETY  = true
        // If you don't want a timer to be ran each instance
        // set this to true.
        private constant boolean SINGLE_TIMER = true
        // If you chose a single timer then this will be the speed
        // at which the timer will update
        private constant real    UPDATE_PERIOD = 0.05
    endglobals
    
    // here you may add or remove handle types
    //! runtextmacro TIMEDHANDLES("effect", "DestroyEffect")
    //! runtextmacro TIMEDHANDLES("lightning", "DestroyLightning")
    //! runtextmacro TIMEDHANDLES("weathereffect", "RemoveWeatherEffect")
    //! runtextmacro TIMEDHANDLES("item", "RemoveItem")
    //! runtextmacro TIMEDHANDLES("unit", "RemoveUnit")
    //! runtextmacro TIMEDHANDLES("ubersplat", "DestroyUbersplat")
    
    // Do not edit below this line
    
    //! textmacro TIMEDHANDLES takes HANDLE,DESTROY
        
        struct $HANDLE$Timed
        
            $HANDLE$ $HANDLE$_var
            static integer index = -1
            static thistype array instance
            
            static if SINGLE_TIMER then
                static timer timer = CreateTimer()
                real duration
                real elapsed = 0
            else static if not LIBRARY.TimerUtils then
                static hashtable table = InitHashtable()
            endif
            
            method destroy takes nothing returns nothing
                static if NULL_SAFETY then
                    if (this.$HANDLE$_var != null) then
                        call $DESTROY$(this.$HANDLE$_var)
                        set this.$HANDLE$_var = null
                    else
                    endif
                else
                    call $DESTROY$(this.$HANDLE$_var)
                endif
                
                static if SINGLE_TIMER then
                    set this.elapsed = 0
                endif
                
                call this.deallocate()
            endmethod
            
            private static method remove takes nothing returns nothing
                static if SINGLE_TIMER then
                    local integer i = 0
                    local thistype this
                    loop
                        exitwhen i > thistype.index
                        set this = instance[i]
                        set this.elapsed = this.elapsed + UPDATE_PERIOD
                        if (this.elapsed >= this.duration) then
                            set instance[i] = instance[index]
                            set i = i - 1
                            set index = index - 1
                            call this.destroy()
                            if (index == -1) then
                                call PauseTimer(thistype.timer)
                            endif
                        endif
                        set i = i + 1
                    endloop
                else
                    local timer t = GetExpiredTimer()
                    static if LIBRARY.TimerUtils then
                        local $HANDLE$Timed this = GetTimerData(t)
                        call ReleaseTimer(t)
                        call this.destroy()
                    else
                        local $HANDLE$Timed this = LoadInteger(table, 0, GetHandleId(t))
                        call DestroyTimer(t)
                        set t = null
                        call this.destroy()
                    endif
                endif
            endmethod
            
            static method create takes $HANDLE$ h, real timeout returns $HANDLE$Timed
                local $HANDLE$Timed this = $HANDLE$Timed.allocate()
                
                static if SINGLE_TIMER then
                    set index = index + 1
                    set instance[index] = this
                    if (index == 0) then
                        call TimerStart(thistype.timer, UPDATE_PERIOD, true, function thistype.remove)
                    endif
                    set this.duration = timeout
                else
                    static if LIBRARY.TimerUtils then
                        call TimerStart(NewTimerEx(this), timeout, false, function $HANDLE$timed.remove)
                    else
                        local timer t = CreateTimer()
                        call SaveInteger(thistype.table, 0, GetHandleId(t), this)
                        call TimerStart(t, timeout, false, function $HANDLE$Timed.remove)
                        set t = null
                    endif
                endif  
                
                set this.$HANDLE$_var = h
                
                return this
            endmethod
            
        endstruct
        
        function $DESTROY$Timed takes $HANDLE$ h, real duration returns $HANDLE$Timed
            return $HANDLE$Timed.create(h, duration)
        endfunction

    //! endtextmacro
    
endlibrary

Collapse JASS:

    call DestroyEffectTimed(AddSpecialEffect("effect.mdx", 0, 0), 5)
    call DestroyLightningTimed(AddLightning("CLPB", true, 0, 0, 100, 100), 5)
    call RemoveUnitTimed(CreateUnit(Player(0), 'hfoo', 0, 0 ,0), 5)
    call RemoveItemTimed(CreateItem('ratf', 0, 0), 60)
04-13-2009, 03:57 AM#2
Rising_Dusk
Expand JASS:
04-13-2009, 04:00 AM#3
TriggerHappy
thanks for that dusk, for those who don't know, I never needed to store the timer, since I use GetExpiredTimer anyways.
04-13-2009, 04:07 AM#4
Rising_Dusk
Expand JASS:
Maybe I didn't fail this time.
Quote:
Originally Posted by TriggerHappy187
I never needed to store the timer, since I use GetExpiredTimer anyways.
Yeah, IRC development ftw.
04-13-2009, 04:26 AM#5
TriggerHappy
Quote:
Maybe I didn't fail this time.

Not entirely :P

You try to destroy the struct instance, not the handle.

You also allocate the struct in teh create function, instead of creating it.

Other than that it's fine.
04-13-2009, 10:33 AM#6
DioD
Totaly useless.

"Timed leaks episode 2"

ExecuteFunc() + TriggerSleepAction() == profit.

profit + textmacro == hurge profit without any other system timers and anything from "advanced vJASS coding"
04-13-2009, 11:02 AM#7
grim001
Quote:
Originally Posted by DioD
ExecuteFunc() + TriggerSleepAction() == profit.

profit + textmacro == hurge profit without any other system timers and anything from "advanced vJASS coding"

If you are fine with imprecise timing and the inability to wait less than ~0.25 sec and you hate vJASS, the scripts section is probably not a good place for you to be visiting or posting in.
04-13-2009, 11:30 AM#8
Troll-Brain
And also if you want a wait still running when the game is paused ...
It does what it say and could be useful, i would say "why not ?"
04-13-2009, 02:39 PM#9
Rising_Dusk
Vex, Ani, and I were all discussing the usefulness of this in IRC and apparently it wasn't useless for us, so. Oh, Vex also said last night that if he added more handles to this that he would approve it. Well he added more handles, but Vex probably went to sleep or something. This is ready for approval, I just have one request based on the documentation:

Collapse JASS:
//*  All this script does is start a timer attached to a handle
//*  and destroys the handl after the timer expires.
Technically, this script associates a handle to a timer and then destroys the handle upon the timer's expiration, you should update that to better describe it (and fix spelling errors). Also, if you could add an example to your documentation, that'd be great. Right now you just list StartHandle$NAME$, which is correct but potentially confusing. Add an example like the following to your documentation:
Collapse JASS:
call StartTimedEffect(AddSpecialEffect("SomeFile.mdx", x, y), 2.)
call StartTimedEffect(AddSpecialEffectTarget("SomeFile.mdx", SomeUnit, "chest"), 2.)
Do all that and I'll approve this.
04-13-2009, 03:44 PM#10
Rising_Dusk
Also, I was thinking (and chatting with Ani about it), you should change your function name from StartTimed$NAME$ since it really isn't fluid with standard WC3 functions for destroying handles.

Consider what WC3 does:
Expand JASS:
This is my suggestion for you:
Expand JASS:
Therefore your code would have the function named:
Expand JASS:
Do that change too if you would. Also, you should make the prefix a textmacro parameter, that way it is consistent with Blizzard. Notice how removing an item is RemoveItem and not Destroyitem, etc.

Like this:
Expand JASS:
04-13-2009, 04:28 PM#11
Deaod
Dusk, how about this one:
Expand Code:
04-13-2009, 04:46 PM#12
Rising_Dusk
Ooooh, yes. I like that one even more. I had noticed there was some overlap, but I forgot that 2+2=4. Yeah, Trigger, do what Deaod suggests.
04-13-2009, 10:52 PM#13
TriggerHappy
I bring updates!
04-14-2009, 02:12 AM#14
Deaod
that NAME parameter is solely for internal naming, why dont you delete it?
04-14-2009, 02:58 AM#15
TriggerHappy
Quote:
Originally Posted by Deaod
that NAME parameter is solely for internal naming, why dont you delete it?

Done, thanks for noticing that.