Cohadar
master of fugue
- Reaction score
- 209
v4.1 (compatibility release for patch 1.23b)
v4.0
This version is a merge of TT v3.4 and ABCT v3.0
Bonus is a support for TimerDialogs.
Function signatures: (for tesh custom highlighting)
In the demo map you will find examples for all possible uses of this system.
Please consult the demo map before asking "how do I .." questions.
JASS:
//==============================================================================
// TT -- TIMER TICKER SYSTEM BY COHADAR -- v4.1
//==============================================================================
//
// PURPOUSE OF TT:
// * Passing data to timers
// * Avoiding direct use of timer handles
//
// PROS:
// * It is easier than using attaching
// * It is optimized to use only one timer on default high frequency
// * GetData method is the same for all timer frequencies
//
// CONS:
// * You must remember to always return true from your function
// when you want to stop timer, even if it is of one-shot type.
// (otherwise it will leak)
//
// START FUNCTIONS:
// * TT_Start(userFunc, struct)
// * TT_StartEx(userFunc, struct, period)
// * TT_Once(userFunc, struct, timeout)
// * TT_StartTimerDialog(userFunc, struct, timeout) -> timerdialog
//
// * userFunc is a user function that takes nothing and returns boolean
// it will be periodically called by the system until it returns true.
//
// GET FUNCTIONS:
// * TT_GetData() -> struct
// * TT_GetTimerDialog() -> timerdialog
//
// * These functions can only be called from inside userFunc
// TT_GetData() will return struct passed to any of the start functions
// TT_GetTimerDialog() returns timerdialog created by TT_StartTimerDialog
//
// DETAILS:
// * On default frequency all user functions are stored in an array.
// Timer will call all those functions each period.
//
// * While user function returns false timer will continue to call it each period
// Once user function returns true it will be removed from system
//
// * TT is using smart timer preloading and simple hash
// When colliding timer handle is found that timer is simply discarded
//
// REQUIREMENTS:
// * NewGen v4c and above (there might be some problems with older NewGen's)
//
// HOW TO IMPORT:
// * Just create a trigger named TT
// * convert it to text and replace the whole trigger text with this one
//
//==============================================================================
library TT initializer Init
//==============================================================================
// Configuration
//==============================================================================
globals
// List of recommended periods for high-frequency timer:
// 0.04 = 25 calls per second
// 0.03125 = 32 calls per second
// 0.025 = 40 calls per second
// 0.02 = 50 calls per second
public constant real PERIOD = 0.03125
// how many low-frequency timers to preload
// system can safely extend beyond this limit
private constant integer PRELOAD = 32
endglobals
//==============================================================================
// End of Configuration
//==============================================================================
//==============================================================================
globals
// "frames per second" of high-frequency timer
public constant integer FPS = R2I(1.0/PERIOD)
// globals for passing data to userFunc
private integer Data
private timerdialog timerDialog
// One Timer to rule them all, One Timer to find them,
// One Timer to call them all and in the jass bind them
// In the land of warcraft where the desyncs lie.
private timer HF_Timer = CreateTimer()
private integer HF_Counter = 0
private trigger array HF_Triggz
private integer array HF_Dataz
// we can safely use dummy hashing here because timers are preloaded
private constant integer LF_HASH = 8191
private integer array LF_Dataz
private trigger array LF_Triggz
private timer array LF_Timerz
private timerdialog array LF_Dialogz
// recycling
private integer array LF_Indexz
private integer LF_Counter = PRELOAD
endglobals
//==============================================================================
// note how colliding timer handles are discarded
// so TT would work properly even after preload limit break
//==============================================================================
private function NewIndex takes nothing returns integer
local integer i
local timer t
if (LF_Counter==0) then
loop
debug call BJDebugMsg("WARNING: TT reached preloaded timer limit!")
set t = CreateTimer()
set i = GetHandleId(t)
set i = i - (i / LF_HASH) * LF_HASH // dummy modulo hash
if LF_Timerz<i> == null then
set LF_Timerz<i> = t
set LF_Triggz<i> = CreateTrigger()
return i
endif
endloop
endif
set LF_Counter = LF_Counter - 1
return LF_Indexz[LF_Counter]
endfunction
//==============================================================================
private function HF_Handler takes nothing returns nothing
local trigger swap
local integer i = HF_Counter
loop
exitwhen i<=0
set Data = HF_Dataz<i>
if TriggerEvaluate(HF_Triggz<i>) then
set swap = HF_Triggz<i>
call TriggerClearConditions(swap)
set HF_Triggz<i> = HF_Triggz[HF_Counter]
set HF_Triggz[HF_Counter] = swap
set HF_Dataz<i> = HF_Dataz[HF_Counter]
set HF_Counter = HF_Counter - 1
endif
set i = i - 1
endloop
// who can guess why am I not nulling swap here?
endfunction
//==============================================================================
private function LF_Handler takes nothing returns nothing
local integer i = GetHandleId(GetExpiredTimer())
set i = i - (i / LF_HASH) * LF_HASH // dummy modulo hash
set Data = LF_Dataz<i>
if TriggerEvaluate(LF_Triggz<i>) then
// recycle the trigger and timer
call TriggerClearConditions(LF_Triggz<i>)
call PauseTimer(LF_Timerz<i>)
set LF_Indexz[LF_Counter] = i
set LF_Counter = LF_Counter + 1
endif
endfunction
//==============================================================================
// Periodic timer that runs on TT_PERIOD
//==============================================================================
public function Start takes code userFunc, integer data returns nothing
debug if userFunc == null then
debug call BJDebugMsg("ERROR: TT_Start - null userFunc")
debug return
debug endif
set HF_Counter = HF_Counter + 1
if HF_Triggz[HF_Counter] == null then
set HF_Triggz[HF_Counter] = CreateTrigger()
endif
set HF_Dataz[HF_Counter] = data
call TriggerAddCondition(HF_Triggz[HF_Counter], Condition(userFunc))
endfunction
//==============================================================================
// Periodic timer with custom period
//==============================================================================
public function StartEx takes code userFunc, integer data, real period returns nothing
local integer i
debug if userFunc == null then
debug call BJDebugMsg("ERROR: TT_StartEx - null userFunc")
debug return
debug endif
set i = NewIndex()
call TriggerAddCondition(LF_Triggz<i>, Condition(userFunc))
set LF_Dataz<i> = data
call TimerStart(LF_Timerz<i>, period, true, function LF_Handler)
endfunction
//==============================================================================
// One shot timer, remember to return true in userFunc
//==============================================================================
public function Once takes code userFunc, integer data, real timeout returns nothing
local integer i
debug if userFunc == null then
debug call BJDebugMsg("ERROR: TT_Once - null userFunc")
debug return
debug endif
set i = NewIndex()
call TriggerAddCondition(LF_Triggz<i>, Condition(userFunc))
set LF_Dataz<i> = data
call TimerStart(LF_Timerz<i>, timeout, false, function LF_Handler)
endfunction
//==============================================================================
public function StartTimerDialog takes code userFunc, integer data, real timeout returns timerdialog
local integer i
debug if userFunc == null then
debug call BJDebugMsg("ERROR: TT_StartTimerDialog - null userFunc")
debug return null
debug endif
set i = NewIndex()
call TriggerAddCondition(LF_Triggz<i>, Condition(userFunc))
set LF_Dataz<i> = data
call TimerStart(LF_Timerz<i>, timeout, false, function LF_Handler)
set bj_lastCreatedTimerDialog = CreateTimerDialog(LF_Timerz<i>)
set LF_Dialogz<i> = bj_lastCreatedTimerDialog
return bj_lastCreatedTimerDialog
endfunction
//==============================================================================
// Call this function only inside the userFunc
//==============================================================================
public function GetData takes nothing returns integer
return Data
endfunction
//==============================================================================
// Call this function only inside the userFunc
//==============================================================================
public function GetTimerDialog takes nothing returns timerdialog
local integer i = GetHandleId(GetExpiredTimer())
set i = i - (i / LF_HASH) * LF_HASH // dummy modulo hash
return LF_Dialogz<i>
endfunction
//==============================================================================
// Preload LF timers and start HF timer.
//==============================================================================
private function Init takes nothing returns nothing
local integer i
local timer t
local integer j = 0
loop
exitwhen j>=PRELOAD
set t = CreateTimer()
set i = GetHandleId(t)
set i = i - (i / LF_HASH) * LF_HASH // dummy modulo hash
if LF_Timerz<i> == null then
set LF_Timerz<i> = t
set LF_Triggz<i> = CreateTrigger()
set LF_Indexz[j] = i
set j = j + 1
endif
endloop
call TimerStart(HF_Timer, PERIOD, true, function HF_Handler)
endfunction
endlibrary
//==============================================================================
// END OF TIMER TICKER SYSTEM
//==============================================================================
</i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i>
v4.0
JASS:
//==============================================================================
// TT -- TIMER TICKER SYSTEM BY COHADAR -- v4.0
//==============================================================================
//
// PURPOUSE OF TT:
// * Passing data to timers
// * Avoiding direct use of timer handles
//
// PROS:
// * It is easier than using attaching
// * It is optimized to use only one timer on default high frequency
// * GetData method is the same for all timer frequencies
//
// CONS:
// * You must remember to always return true from your function
// when you want to stop timer, even if it is of one-shot type.
// (otherwise it will leak)
//
// START FUNCTIONS:
// * TT_Start(userFunc, struct)
// * TT_StartEx(userFunc, struct, period)
// * TT_Once(userFunc, struct, timeout)
// * TT_StartTimerDialog(userFunc, struct, timeout) -> timerdialog
//
// * userFunc is a user function that takes nothing and returns boolean
// it will be periodically called by the system until it returns true.
//
// GET FUNCTIONS:
// * TT_GetData() -> struct
// * TT_GetTimerDialog() -> timerdialog
//
// * These functions can only be called from inside userFunc
// TT_GetData() will return struct passed to any of the start functions
// TT_GetTimerDialog() returns timerdialog created by TT_StartTimerDialog
//
// DETAILS:
// * On default frequency all user functions are stored in an array.
// Timer will call all those functions each period.
//
// * While user function returns false timer will continue to call it each period
// Once user function returns true it will be removed from system
//
// * TT is using smart timer preloading and simple hash
// When colliding timer handle is found that timer is simply discarded
//
// REQUIREMENTS:
// * NewGen v4c and above (there might be some problems with older NewGen's)
//
// HOW TO IMPORT:
// * Just create a trigger named TT
// * convert it to text and replace the whole trigger text with this one
//
//==============================================================================
library TT initializer Init
//==============================================================================
// Configuration
//==============================================================================
globals
// List of recommended periods for high-frequency timer:
// 0.04 = 25 calls per second
// 0.03125 = 32 calls per second
// 0.025 = 40 calls per second
// 0.02 = 50 calls per second
public constant real PERIOD = 0.03125
// how many low-frequency timers to preload
// system can safely extend beyond this limit
private constant integer PRELOAD = 32
endglobals
//==============================================================================
// End of Configuration
//==============================================================================
//==============================================================================
globals
// "frames per second" of high-frequency timer
public constant integer FPS = R2I(1.0/PERIOD)
// globals for passing data to userFunc
private integer Data
private timerdialog timerDialog
// One Timer to rule them all, One Timer to find them,
// One Timer to call them all and in the jass bind them
// In the land of warcraft where the desyncs lie.
private timer HF_Timer = CreateTimer()
private integer HF_Counter = 0
private trigger array HF_Triggz
private integer array HF_Dataz
// we can safely use dummy hashing here because timers are preloaded
private constant integer LF_HASH = 8191
private integer array LF_Dataz
private trigger array LF_Triggz
private timer array LF_Timerz
private timerdialog array LF_Dialogz
// recycling
private integer array LF_Indexz
private integer LF_Counter = PRELOAD
endglobals
//==============================================================================
private constant function H2I takes handle h returns integer
return h
return 0
endfunction
//==============================================================================
// note how colliding timer handles are discarded
// so TT would work properly even after preload limit break
//==============================================================================
private function NewIndex takes nothing returns integer
local integer i
local timer t
if (LF_Counter==0) then
loop
debug call BJDebugMsg("WARNING: TT reached preloaded timer limit!")
set t = CreateTimer()
set i = H2I(t)
set i = i - (i / LF_HASH) * LF_HASH // dummy modulo hash
if LF_Timerz<i> == null then
set LF_Timerz<i> = t
set LF_Triggz<i> = CreateTrigger()
return i
endif
endloop
endif
set LF_Counter = LF_Counter - 1
return LF_Indexz[LF_Counter]
endfunction
//==============================================================================
private function HF_Handler takes nothing returns nothing
local trigger swap
local integer i = HF_Counter
loop
exitwhen i<=0
set Data = HF_Dataz<i>
if TriggerEvaluate(HF_Triggz<i>) then
set swap = HF_Triggz<i>
call TriggerClearConditions(swap)
set HF_Triggz<i> = HF_Triggz[HF_Counter]
set HF_Triggz[HF_Counter] = swap
set HF_Dataz<i> = HF_Dataz[HF_Counter]
set HF_Counter = HF_Counter - 1
endif
set i = i - 1
endloop
// who can guess why am I not nulling swap here?
endfunction
//==============================================================================
private function LF_Handler takes nothing returns nothing
local integer i = H2I(GetExpiredTimer())
set i = i - (i / LF_HASH) * LF_HASH // dummy modulo hash
set Data = LF_Dataz<i>
if TriggerEvaluate(LF_Triggz<i>) then
// recycle the trigger and timer
call TriggerClearConditions(LF_Triggz<i>)
call PauseTimer(LF_Timerz<i>)
set LF_Indexz[LF_Counter] = i
set LF_Counter = LF_Counter + 1
endif
endfunction
//==============================================================================
// Periodic timer that runs on TT_PERIOD
//==============================================================================
public function Start takes code userFunc, integer data returns nothing
debug if userFunc == null then
debug call BJDebugMsg("ERROR: TT_Start - null userFunc")
debug return
debug endif
set HF_Counter = HF_Counter + 1
if HF_Triggz[HF_Counter] == null then
set HF_Triggz[HF_Counter] = CreateTrigger()
endif
set HF_Dataz[HF_Counter] = data
call TriggerAddCondition(HF_Triggz[HF_Counter], Condition(userFunc))
endfunction
//==============================================================================
// Periodic timer with custom period
//==============================================================================
public function StartEx takes code userFunc, integer data, real period returns nothing
local integer i
debug if userFunc == null then
debug call BJDebugMsg("ERROR: TT_StartEx - null userFunc")
debug return
debug endif
set i = NewIndex()
call TriggerAddCondition(LF_Triggz<i>, Condition(userFunc))
set LF_Dataz<i> = data
call TimerStart(LF_Timerz<i>, period, true, function LF_Handler)
endfunction
//==============================================================================
// One shot timer, remember to return true in userFunc
//==============================================================================
public function Once takes code userFunc, integer data, real timeout returns nothing
local integer i
debug if userFunc == null then
debug call BJDebugMsg("ERROR: TT_Once - null userFunc")
debug return
debug endif
set i = NewIndex()
call TriggerAddCondition(LF_Triggz<i>, Condition(userFunc))
set LF_Dataz<i> = data
call TimerStart(LF_Timerz<i>, timeout, false, function LF_Handler)
endfunction
//==============================================================================
public function StartTimerDialog takes code userFunc, integer data, real timeout returns timerdialog
local integer i
debug if userFunc == null then
debug call BJDebugMsg("ERROR: TT_StartTimerDialog - null userFunc")
debug return null
debug endif
set i = NewIndex()
call TriggerAddCondition(LF_Triggz<i>, Condition(userFunc))
set LF_Dataz<i> = data
call TimerStart(LF_Timerz<i>, timeout, false, function LF_Handler)
set bj_lastCreatedTimerDialog = CreateTimerDialog(LF_Timerz<i>)
set LF_Dialogz<i> = bj_lastCreatedTimerDialog
return bj_lastCreatedTimerDialog
endfunction
//==============================================================================
// Call this function only inside the userFunc
//==============================================================================
public function GetData takes nothing returns integer
return Data
endfunction
//==============================================================================
// Call this function only inside the userFunc
//==============================================================================
public function GetTimerDialog takes nothing returns timerdialog
local integer i = H2I(GetExpiredTimer())
set i = i - (i / LF_HASH) * LF_HASH // dummy modulo hash
return LF_Dialogz<i>
endfunction
//==============================================================================
// Preload LF timers and start HF timer.
//==============================================================================
private function Init takes nothing returns nothing
local integer i
local timer t
local integer j = 0
loop
exitwhen j>=PRELOAD
set t = CreateTimer()
set i = H2I(t)
set i = i - (i / LF_HASH) * LF_HASH // dummy modulo hash
if LF_Timerz<i> == null then
set LF_Timerz<i> = t
set LF_Triggz<i> = CreateTrigger()
set LF_Indexz[j] = i
set j = j + 1
endif
endloop
call TimerStart(HF_Timer, PERIOD, true, function HF_Handler)
endfunction
endlibrary
//==============================================================================
// END OF TIMER TICKER SYSTEM
//==============================================================================
</i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i>
This version is a merge of TT v3.4 and ABCT v3.0
Bonus is a support for TimerDialogs.
Function signatures: (for tesh custom highlighting)
JASS:
function TT_Start takes code userFunc, integer data returns nothing
function TT_StartEx takes code userFunc, integer data, real period returns nothing
function TT_Once takes code userFunc, integer data, real timeout returns nothing
function TT_StartTimerDialog takes code userFunc, integer data, real timeout returns timerdialog
function TT_GetData takes nothing returns integer
function TT_GetTimerDialog takes nothing returns timerdialog
In the demo map you will find examples for all possible uses of this system.
Please consult the demo map before asking "how do I .." questions.