HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

LoopCode

09-03-2016, 12:48 PM#1
AGD
This system allows you to register a code that will run every specified timeout. Note that this system only uses one timer for all registered codes. Therefore, codes with periods indivisible by 0.03125 doesn't run with a constant time interval. Although the difference will not exceed 0.03125, you probably don't want it to be that way. But this will not be much of a problem for codes with low frequency period such as those with timeouts greater than 2 seconds since the difference wouldn't be so noticeable.

In short, this works best for codes with timeout divisible by 0.03125 seconds.

Code:
Collapse JASS:
library LoopCode// v1.1


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

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

      function interface LoopCode takes nothing returns nothing/*
        - Interface of functions to be registered in the loop

    */function RegisterLoopCode takes LoopCode c, real timeout returns boolean/*
        - Registers a code to run every <timeout> seconds and returns a boolean value depending
        on the success of the operation

    */function RemoveLoopCode takes LoopCode c returns boolean/*
        - Unregisters a code from the loop and returns a boolean value depending
        on the success of the operation

    */function SetCodeTimeout takes LoopCode c, real timeout returns boolean/*
        - Sets a new loop timeout for a code

    *///! endnovjass

    //=================================== Configuration ====================================

    globals

        ////////////////////////////////////////////////////////////////////////
        // The minimum possible timeout of the loop                           //
        ////////////////////////////////////////////////////////////////////////
        private constant real TIMEOUT = 0.03125
        ////////////////////////////////////////////////////////////////////////
        // If true, the code timeout will be automatically set to the minimum //
        // amount if the input timeout value is less than <TIMEOUT>           //
        ////////////////////////////////////////////////////////////////////////
        private constant boolean AUTO_ADJUST = true

    endglobals

    //================================ End of Configuration ================================

    globals
        private LoopCode array codes
        private timer Timer = CreateTimer()
        private integer id = 0
        private integer count = 0
        private real array codeTimeout
        private real array elapsed
        private integer array index
        private boolean array check
    endglobals

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

    function interface LoopCode takes nothing returns nothing

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

    private function RunLoop takes nothing returns nothing
        set id = 0
        loop
            set id = id + 1
            set elapsed[id] = elapsed[id] + TIMEOUT
            if elapsed[id] >= codeTimeout[id] then
                call codes[id].evaluate()
                set elapsed[id] = elapsed[id] - codeTimeout[id]
            endif
            exitwhen id == count
        endloop
    endfunction

    function RegisterLoopCode takes LoopCode c, real timeout returns boolean
        static if AUTO_ADJUST then
            if timeout < TIMEOUT then
                set timeout = TIMEOUT
                debug call Debug("Entered code execution timeout is less than the minimum value (" + R2S(TIMEOUT) + "), auto-adjusting timeout to (" + R2S(TIMEOUT) + ")")
            endif
        else
            if timeout < TIMEOUT then
                debug call Debug("ERROR: Entered code execution timeout is less than the minimum value (" + R2S(TIMEOUT) + ")")
                return false
            endif
        endif
        if not check[c] then
            debug if timeout - (timeout/TIMEOUT)*TIMEOUT > 0.00 then
                debug call Debug("WARNING: Entered code timeout is not divisible by " + R2S(TIMEOUT) + ", this code's execution interval will not be even")
            debug endif
            set count = count + 1
            set elapsed[count] = 0.00
            set codeTimeout[count] = timeout
            set codes[count] = c
            set index[c] = count
            set check[c] = true
            if count == 1 then
                call TimerStart(Timer, TIMEOUT, true, function RunLoop)
                debug call Debug("There is one code instance registered, starting to run timer")
            endif
            return true
        endif
        debug call Debug("ERROR: Attempt to double register a code")
        return false
    endfunction

    function RemoveLoopCode takes LoopCode c returns boolean
        local integer i = index[c]
        if check[c] then
            debug call Debug("Removing a code from the loop")
            set check[c] = false
            set index[codes[count]] = i
            set codes[i] = codes[count]
            set codeTimeout[i] = codeTimeout[count]
            if id >= i then
                set id = id - 1
            endif
            set count = count - 1
            if count == 0 then
                call TimerStart(Timer, 0, false, null)
                debug call Debug("There are no code instances running, stopping timer")
            endif
            return true
        endif
        debug call Debug("ERROR: Attempt to remove a null or an already removed code")
        return false
    endfunction

    function SetCodeTimeout takes LoopCode c, real timeout returns boolean
        local integer i = index[c]
        if check[c] then
            static if AUTO_ADJUST then
                if codeTimeout[i] >= TIMEOUT then
                    set codeTimeout[i] = timeout
                else
                    set codeTimeout[i] = TIMEOUT
                    debug call Debug("Entered code execution timeout is less than the minimum value (" + R2S(TIMEOUT) + "), auto-adjusting timeout to (" + R2S(TIMEOUT) + ")")
                endif
                return true
            else
                if codeTimeout[i] >= TIMEOUT then
                    set codeTimeout[i] = timeout
                    return true
                endif
                debug call Debug("ERROR: Entered code execution timeout is less than the minimum value (" + R2S(TIMEOUT) + ")")
                return false
            endif
        endif
        debug call Debug("ERROR: Specified code is not registered")
        return false
    endfunction


endlibrary
09-07-2016, 02:57 PM#2
AGD
Updated to v1.1
- fixed some minor errors regarding the id in RunLoop not being decreased by 1 when a code is removed from the loop