Warcraft III resources & community, 2003–2006 · archived

CreateThreadScopeVariable

not rated
Submitted by AltSubmitterVariable Change0 downloads
Copy and paste all of this code into your custom script area, and you will now be able to create variables of "thread" scope.

Q: What is thread scope?

A: Globals can be used anywhere, locals can only be used within the function they're created in, and similarly threadvars can only be used within the thread in which they were created. By thread I mean specific instance of the trigger running. Think of it as a variable with trigger scope, but if two instances of the same trigger are running at the same time, they each have their own separate trigger scope (the thread scope).


Q: Which functions should I actually care about?

The CreateThreadXXXX functions, which let you declare the variable. Simply pass them a string for what you want to be the variable to be named.

The SetThreadXXXX functions, simply pass the name of the variable as a string the value you want to set it too.

The GetThreadXXXX functions, simply pass the the name of the variable you want as a string to get their value.

The AttachTimer2CurrentThread function, which lets this work with timers. Timers are technically their own threads, but this will let you share values between your current thread and a timer. Be sure to read the comments about FlushTimerAttachments and FlushThreadVars though.

The FlushThreadVars function. Call this at the end of all your triggers that use these thread vars to clean up after yourself. Unfortunately there's no way to automate this.

The FlushTimerAttachments function. Call this when you're done sharing timers between a thread and a timer function.


Q: What would I use this for?

A: This is really useful when messing with callback functions, because they can't take parameters. Now you don't have to use the bj_ globals as a workaround or worry about triggers with lots of oddly placed waits.


Q: How do I use this for types that aren't supported?

A: You should be able to store almost any type by using the H2I function to convert the other types to integers. You will need another return bug exploiting function to convert them back.


Q: How does this work under the hood?

A: Read the comments, but in short in creates a unique game cache for every thread running.


Q: If this works via the game cache, why doesn't it support storing unit variables?

A: Because the cache won't actually store unit variables, it stores real copies of the units, not references to them. Instead use H2I to convert unit vars to integers, store the integer in a thread var, later retrieve it, then make a I2U return bug exploiting function to convert them back.

Source

//***************************************************
//*
//*  Thread Scope engine functions
//*
//***************************************************

//Return bug exploit to help with GetThreadIndexString
function H2I takes handle whichHandle returns integer
    return whichHandle
    return 0
endfunction

//Generates a unique string for every thread. Could be inlined for better performance
//Has to be written this way so that certain trigger numbers + execution counts
//don't overlap values. The pipe is there to make sure digit combination doesn't
//cause value repeats. There maybe a more optimal way to do this.
function GetThreadIndexString takes nothing returns string
    local integer triggerInteger = H2I(GetTriggeringTrigger())
    local gamecache pointerCache

    //Only true if being called inside a TimerStart thread
    //For use with AttachTimer2CurrentThread()
    if(triggerInteger == 0) then
        set pointerCache = InitGameCache("pointerCache.w3v")
        return GetStoredString(pointerCache, "timerPointers", I2S(H2I(GetExpiredTimer())))
    endif

    return (I2S(triggerInteger) + "|" + I2S(GetTriggerExecCount(GetTriggeringTrigger())))
endfunction

//Timers are technically separate threads, but because they use callback functions,
//you'll often want to use them the same way. So this attaches the pointer to the thread
//from which the function is called, meaning that if you store variables in the current
//thread, you will then be able to retrieve just like you normally do inside the function
//that you've told TimerStart to run when the timer expires.
//WARNING: Do not call FlushThreadVars() at the end of the thread if the timer is going to expire
//after the thread finishes. Instead call inside timer function.
function AttachTimer2CurrentThread takes timer whichTimer returns nothing
    call StoreString(InitGameCache("pointerCache.w3v"), "timerPointers", I2S(H2I(whichTimer)), GetThreadIndexString())
endfunction

//For any trigger you use thread scope variables in, make sure you run this to clean up
//after yourself. Seeing as it's trigger scope it makes the most sense to just always make
//this the last action in your trigger
//WARNING: IF CALLING FROM INSIDE A TIMER FUNCTION, be sure to call BEFORE you remove the timer
function FlushThreadVars takes nothing returns nothing
   call FlushGameCache(InitGameCache(GetThreadIndexString()))
endfunction

//Only call this inside the timer function itself.
//Needs to be called IN ADDITION TO FlushThreadVars() if you attach timers
function FlushTimerAttachments takes nothing returns nothing
    call FlushStoredString(InitGameCache("pointerCache.w3v"), "timerPointers", I2S(H2I(GetExpiredTimer())))
endfunction

//***************************************************
//*
//*  ThreadInteger functions
//*
//***************************************************

//Returns 1 if there's an error (variable already exists)
function CreateThreadInteger takes string varName, integer initValue returns integer
    local gamecache threadCache = InitGameCache(GetThreadIndexString())

    //Could remove this error check for better performance, but be careful
    if(HaveStoredInteger(threadCache, "integer", varName) == true) then
        return 1
    else
        call StoreInteger(threadCache, "integer", varName, initValue)
    endif

    return 0
endfunction

//Returns 1 if there is an error (variable does not exist)
function SetThreadInteger takes string varName, integer value returns integer
    local gamecache threadCache = InitGameCache(GetThreadIndexString())

    //Could remove this error check for better performance, but be careful
    if(HaveStoredInteger(threadCache, "integer", varName) == true) then
        call StoreInteger(threadCache, "integer", varName, value)
    else
        return 1
    endif

    return 0
endfunction

//Does not return an error, because it'd be indistinguishable from a stored value
//Cache function automatically returns 0 if the var doesn't exist
function GetThreadInteger takes string varName returns integer
    return GetStoredInteger(InitGameCache(GetThreadIndexString()), "integer", varName)
endfunction


//***************************************************
//*
//*  ThreadReal functions
//*
//***************************************************

//Returns 1 if there's an error (variable already exists)
function CreateThreadReal takes string varName, real initValue returns integer
    local gamecache threadCache = InitGameCache(GetThreadIndexString())

    //Could remove this error check for better performance, but be careful
    if(HaveStoredReal(threadCache, "real", varName) == true) then
        return 1
    else
        call StoreReal(threadCache, "real", varName, initValue)
    endif

    return 0
endfunction

//Returns 1 if there is an error (variable does not exist)
function SetThreadReal takes string varName, real value returns integer
    local gamecache threadCache = InitGameCache(GetThreadIndexString())

    //Could remove this error check for better performance, but be careful
    if(HaveStoredReal(threadCache, "real", varName) == true) then
        call StoreReal(threadCache, "real", varName, value)
    else
        return 1
    endif

    return 0
endfunction

//Does not return an error, because it'd be indistinguishable from a stored value
//Cache function automatically returns 0 if the var doesn't exist
function GetThreadReal takes string varName returns real
    return GetStoredReal(InitGameCache(GetThreadIndexString()), "real", varName)
endfunction


//***************************************************
//*
//*  ThreadBoolean functions
//*
//***************************************************

//Returns 1 if there's an error (variable already exists)
function CreateThreadBoolean takes string varName, boolean initValue returns integer
    local gamecache threadCache = InitGameCache(GetThreadIndexString())

    //Could remove this error check for better performance, but be careful
    if(HaveStoredBoolean(threadCache, "boolean", varName) == true) then
        return 1
    else
        call StoreBoolean(threadCache, "boolean", varName, initValue)
    endif

    return 0
endfunction

//Returns 1 if there is an error (variable does not exist)
function SetThreadBoolean takes string varName, boolean value returns integer
    local gamecache threadCache = InitGameCache(GetThreadIndexString())

    //Could remove this error check for better performance, but be careful
    if(HaveStoredBoolean(threadCache, "boolean", varName) == true) then
        call StoreBoolean(threadCache, "boolean", varName, value)
    else
        return 1
    endif

    return 0
endfunction

//Does not return an error, because it'd be indistinguishable from a stored value
//Cache function automatically returns 0 if the var doesn't exist
function GetThreadBoolean takes string varName returns boolean
    return GetStoredBoolean(InitGameCache(GetThreadIndexString()), "boolean", varName)
endfunction



//***************************************************
//*
//*  ThreadString functions
//*
//***************************************************

//Returns 1 if there's an error (variable already exists)
function CreateThreadString takes string varName, string initValue returns integer
    local gamecache threadCache = InitGameCache(GetThreadIndexString())

    //Could remove this error check for better performance, but be careful
    if(HaveStoredString(threadCache, "string", varName) == true) then
        return 1
    else
        call StoreString(threadCache, "string", varName, initValue)
    endif

    return 0
endfunction

//Returns 1 if there is an error (variable does not exist)
function SetThreadString takes string varName, string value returns integer
    local gamecache threadCache = InitGameCache(GetThreadIndexString())

    //Could remove this error check for better performance, but be careful
    if(HaveStoredString(threadCache, "string", varName) == true) then
        call StoreString(threadCache, "string", varName, value)
    else
        return 1
    endif

    return 0
endfunction

//Does not return an error, because it'd be indistinguishable from a stored value
//Cache function automatically returns 0 if the var doesn't exist
function GetThreadString takes string varName returns string
    return GetStoredString(InitGameCache(GetThreadIndexString()), "string", varName)
endfunction

Comments

0

No comments.