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

[Snippet] AppendThread

Ever wanted a zero second timer that didn't have any delay whatsoever? Well now you have it.

AppendThread simply takes a code that you want to run, and runs it after every other queued thread runs first.

This means that damage-blocking engines can now remove the life bonus abilities without risking any kind of split second delay.

It also means more functionality.

It has no requirements, is well-tested and should be implemented right away for anyone who needs to do some after-thread business!

JASS:
library AppendThread requires optional UnitIndexer
 
    /*
        Append a code to the end of the existing thread. This is the perfect
        replacement to 0-second timers as 0-second timers are not immediate.
        Damage blocking systems which need to register INSTANTLY after the
        damage is applied, this is your new best friend.
 
        API
        ***
            function AppendThread
                takes
                    code thread
                        Adds code "thread" to the end of the existing thread.
 
                    integer id
                        A thread id for attaching things like structs.
 
                returns nothing
 
 
            function GetAppendedThreadId
                takes
                    nothing
 
                returns integer
                    Returns the thread id you specified in "AppendThread".
    */
 
    globals
        private constant integer DUMMY_ID = 'uloc' //This should be any unit that has locust
    endglobals
 
    private module M
        static unit u = null
        static force dummyForce = CreateForce()
        static trigger t = CreateTrigger()
        static integer size = 0
        static integer array data
        static boolexpr array eval
 
        static real store = 0   //Keep unit at top left of map.
        static real trip = 0    //Move unit to bottom left of map to fire system.
 
        private static method fire takes nothing returns boolean
            if GetTriggerUnit() == .u then
                call DisableTrigger(.t)
                call SetUnitY(.u, .store)
                loop
                    set .size = .size - 1
                    call ForceEnumPlayersCounted(.dummyForce, .eval[.size], 1)
                    exitwhen .size == 0
                endloop
            endif
            return false
        endmethod
 
        private static method onInit takes nothing returns nothing
            local rect rct = GetWorldBounds()
            local region r = CreateRegion()
            local real x = GetRectMinX(rct) + 32
            set .store = GetRectMaxY(rct) - 32
            //Handle dummy unit that trips the event.
            static if LIBRARY_UnitIndexer then
                set UnitIndexer.enabled = false
            endif
            set .u = CreateUnit(Player(15), DUMMY_ID, x, .store, 0)
            static if LIBRARY_UnitIndexer then
                set UnitIndexer.enabled = true
            endif
            call ShowUnit(.u, false)
            //Handle region that detects the event.
            set .trip = GetRectMinY(rct) + 32
            call SetRect(rct, x - 32, .trip - 32, x + 32, .trip + 32)
            call RegionAddRect(r, rct)
            //Condition for this event fires at end of thread.
            call TriggerRegisterEnterRegion(.t, r, null)
            call TriggerAddCondition(.t, Filter(function thistype.fire))
            call DisableTrigger(.t)
            //----
            call RemoveRect(rct)
            set rct = null
            set r = null
        endmethod
    endmodule
 
    private struct S extends array
        implement M
    endstruct
 
    function AppendThread takes integer id, code c returns nothing
        if S.size == 0 then
            call EnableTrigger(S.t)
            call SetUnitY(S.u, S.trip)
        endif
        set S.data[S.size] = id
        set S.eval[S.size] = Filter(c)
        set S.size = S.size + 1
    endfunction
 
    function GetAppendedThreadId takes nothing returns integer
        return S.data[S.size]
    endfunction
 
endlibrary
 
Level 26
Joined
Aug 18, 2009
Messages
4,097
You know that the enter event does not fire immediately either/has delay?

JASS:
function d takes nothing returns nothing
    call BJDebugMsg("timer")
endfunction

function b takes nothing returns nothing
    call BJDebugMsg("enter")
endfunction

function a takes nothing returns nothing
    call AppendThread(0, function b)
    call TimerStart(CreateTimer(), 0, false, function d)
    call BJDebugMsg("current")
endfunction

Output: current, enter, timer

JASS:
function d takes nothing returns nothing
    call BJDebugMsg("timer")
endfunction

function b takes nothing returns nothing
    call BJDebugMsg("enter")
endfunction

function a takes nothing returns nothing
    call TimerStart(CreateTimer(), 0, false, function d)
    call AppendThread(0, function b)
    call BJDebugMsg("current")
endfunction

Output: current, timer, enter

@Troll-Brain: The event's filter is what fires immediately.
 
WaterKnight, have you tested this since 1.26?

I have tested it with a fast timeout and the "region" event always happened before the 0 second timer. Every time.

I have also experienced a rare, minor HP bar flicker when using 0 second timers to remove the damage blocking ability +500,000. I have tested it extremely thoroughly using AppendThread and have never seen a flicker.

AppendThread, by all accounts, happens exactly at the end of the running thread.
 
Well there is an HP bar flicker sometimes in DamageEngine, there is never an HP bar flicker, ever, in my revised vJass script using AppendThread.

AppendThread is just instant, but it seems that an expiring timer is usually instant, but not always.

EDIT:

Graveyarding this. Somehow I got lucky for the first thousands of tests that I did this, but to my dismay I am seeing the HP bar flicker sometimes now, even with AppendThread.

There is just no fix whatsoever to the HP bar flickering problem.

Seems I was very wrong.
 
Top