TimerIndexer v1.2

Scripts

9 years
edited 8 years
Useful system especially in making an MUI spell which uses timers. Instead of saving the spell data in a hashtable with the handleid of the timer as the parent key, you can just use normal arrays with the timerid as the index. This also allows you to pass custom data (integer) to timers.

System Features:
  • Indexed timers (Array safe, 1-8190 but can also be customized to be 8190+) NEW
  • Timer custom data (integer) attachment [NEW]
  • Timer double free protection
  • Automatic timer replacement (Useful safety feature which automatically replaces timers belonging to this system with a timer of the same timerid and handleid when destroyed)


    Timer Indexer v1.2
    Code (jass) Select
    library TimerIndexer //v1.2


    //! novjass
         ________________
        |                |
        | Written by AGD |
        |________________|


        |=====|
        | API |
        |=====|

            function GetTimer takes nothing returns timer/*
            - Allocates a new usable timer from the stock

          */function GetTimerEx takes integer i returns timer/*
            - Retrieves a new usable timer from the stock and initializes
              its custom integer data to <i>

          */function GetTimerById takes integer i returns timer/*
            - Retrieves a timer of ID <i> from the stock but returns
              null if that timer is not free

          */function FreeTimer takes timer t returns nothing/*
            - Releases the timer back to the stock

          */function GetTimerId takes timer t returns integer/*
            - Returns the index of the timer

          */function GetTimerData takes timer t returns integer/*
            - Returns the custom integer data attached to the timer

          */function SetTimerData takes timer t, integer i returns nothing/*
            - Attaches a custom integer data to the timer

          */function IsTimerStocked takes timer t returns boolean/*
            - Checks if the timer is free

          */function GetTimerFlag takes timer t returns boolean/*
            - Checks if the timer is included in this system's timer stock

    *///! endnovjass

        globals
    /*
            Determines the total number of timers on the stock          */
            private constant integer TIMER_STOCK_SIZE = 8190

    /*      Determines the delay of timer replacement in case a
            timer belonging to the stock is accidentally destroyed
            Note that this value should be greater than the time
            delay of the handleId recycling which is approximately
            0.0050000 ( It's not advised to change this anyway )        */
            private constant real REPLACE_DELAY = 0.0050001

        endglobals

        //================================================================

        globals
            private timer array T[TIMER_STOCK_SIZE]
            private timer tempTimer
            private integer START_HANDLE
            private integer destroyed
            private integer current
            private integer pitStop
            private integer this
            private integer array recycler[TIMER_STOCK_SIZE]
            private integer array data[TIMER_STOCK_SIZE]
            private boolean dont = false
            private boolean array isTimerStocked[TIMER_STOCK_SIZE]
        endglobals

        static if DEBUG_MODE then
            private function Debug takes string msg returns nothing
                call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "|CFFFFCC00[Timer Indexer]|R : " + msg)
            endfunction
        endif

        function GetTimerId takes timer t returns integer
            return GetHandleId(t) - START_HANDLE
        endfunction

        function GetTimerData takes timer t returns integer
            return data[GetTimerId(t)]
        endfunction

        function SetTimerData takes timer t, integer i returns nothing
            set data[GetTimerId(t)] = i
        endfunction

        function IsTimerStocked takes timer t returns boolean
            return isTimerStocked[GetTimerId(t)]
        endfunction

        function GetTimerFlag takes timer t returns boolean
            return GetTimerId(t) > 0 and GetTimerId(t) <= TIMER_STOCK_SIZE
        endfunction

        function GetTimer takes nothing returns timer
            set this = recycler[0]
            set recycler[0] = recycler[this]
            if isTimerStocked[this] then
                set isTimerStocked[this] = false
                debug call Debug("Retrieving Timer [" + I2S(this) + "] from stock")
                return T[this]
            endif
            debug call Debug("ERROR: No free timers available, creating a temporary timer.")
            return CreateTimer()
        endfunction

        function GetTimerById takes integer i returns timer
            if isTimerStocked[i] then
                debug call Debug("Retrieving Timer [" + I2S(i) + "] from stock")
                return T[i]
            endif
            debug if i < 1 or i > TIMER_STOCK_SIZE then
                debug call Debug("ERROR: Specified timer ID is out of bounds")
            debug else
                debug call Debug("ERROR: Timer [" + I2S(i) + "] is not free")
            debug endif
            return null
        endfunction

        function GetTimerEx takes integer i returns timer
            set tempTimer = GetTimer()
            set data[GetTimerId(tempTimer)] = i
            return tempTimer
        endfunction

        function FreeTimer takes timer t returns nothing
            local integer i = GetTimerId(t)
            if not isTimerStocked[i] and GetTimerFlag(t) then
                call TimerStart(t, 0, false, null)
                set isTimerStocked[i] = true
                set data[i] = 0
                set recycler[i] = recycler[0]
                set recycler[0] = i
                debug call Debug("Releasing Timer [" + I2S(i) + "] back to the stock")
            elseif not GetTimerFlag(t) then
                call DestroyTimer(t)
                debug call Debug("ERROR: Freed timer does not belong to the stack, destroying timer")
            debug else
                debug call Debug("ERROR: Attempt to double-free Timer [" + I2S(i) + "]")
            endif
        endfunction

        private function Replace takes nothing returns nothing
            local integer i = destroyed
            set T[i] = CreateTimer()
            if GetTimerId(T[i]) == i then
                set isTimerStocked[i] = true
                debug call Debug("Timer [" + I2S(GetTimerId(T[i])) + "] was replaced")
            else
                debug call Debug("ERROR: Unable to replace Timer [" + I2S(i) + "]")
                set dont = true
                call DestroyTimer(T[i])
                set dont = false
                set T[i] = null
            endif
            call FreeTimer(GetExpiredTimer())
        endfunction

        private function OnDestroy takes timer t returns nothing
            local integer i = GetTimerId(t)
            local trigger trig
            if not dont and GetTimerFlag(t) then
                set T[i] = null
                set isTimerStocked[i] = false
                set destroyed = i
                call DestroyTimer(null)
                call TimerStart(GetTimer(), REPLACE_DELAY, false, function Replace)
                debug call Debug("WARNING: Timer [" + I2S(i) + "] got destroyed!")
                set trig = null
            endif
        endfunction

        hook DestroyTimer OnDestroy

        private function Delegate takes nothing returns nothing
            local integer i = current
            loop
                set i = i + 1
                set T[i] = CreateTimer()
                set isTimerStocked[i] = true
                set recycler[i] = i + 1
                if i == TIMER_STOCK_SIZE then
                    debug call Debug("Total number of timers created: " + I2S(i))
                    debug call Debug("Timer stock count is complete")
                    return
                endif
                exitwhen i == current + pitStop
            endloop
            set current = i
            call Delegate.evaluate()
        endfunction

        private module M
            private static method onInit takes nothing returns nothing
                local integer i = 1
                if TIMER_STOCK_SIZE <= 8190 then
                    set pitStop = TIMER_STOCK_SIZE
                else
                    set pitStop = 1000
                endif
                set recycler[TIMER_STOCK_SIZE] = 0
                set recycler[0] = 1
                set recycler[1] = 2
                set T[i] = CreateTimer()
                set START_HANDLE = GetHandleId(T[i]) - 1
                set isTimerStocked[i] = true
                loop
                    set i = i + 1
                    set T[i] = CreateTimer()
                    set isTimerStocked[i] = true
                    set recycler[i] = i + 1
                    exitwhen i == pitStop
                endloop
                set current = i
                if TIMER_STOCK_SIZE > current then
                    call Delegate.evaluate()
                debug else
                    debug call Debug("Total number of timers created: " + I2S(i))
                    debug call Debug("Timer stock count is complete")
                endif
            endmethod
        endmodule

        private struct S extends array
            implement M
        endstruct

    endlibrary



    Changelogs
    Spoiler

    v1.2
    - Added more functionalities such as attaching custom timer data, now the system comprises all but is not limited to the main functionalities of Vexorian's TimerUtils
    - Optimized the code especially in the part in updating the timer stack
    - Fixed some bugs

    v1.1
    - Added the possibility for users to configure the timer stock size above 8190
    - Some fixes

    v1.0
    - First Release