- Joined
- Nov 7, 2014
- Messages
- 571
Timer - an easy way to use (attaching struct instances/data to timers) and implement timers
Probably many people know/use TimerUtils which provides a nice way to work (attaching struct instances/data) with timers and it's also flexible/configurable. But I think this (the Timer struct) is even nicer (in my opinion =)) to use and in terms of implementation. I see that TimerUtil's implementation complexity comes from it's configurability but it's also a bit confusing, i.e which flavor should I use?
timers.j:
demo (worst demo ever):
Probably many people know/use TimerUtils which provides a nice way to work (attaching struct instances/data) with timers and it's also flexible/configurable. But I think this (the Timer struct) is even nicer (in my opinion =)) to use and in terms of implementation. I see that TimerUtil's implementation complexity comes from it's configurability but it's also a bit confusing, i.e which flavor should I use?
timers.j:
JASS:
library Timers
// Credits:
// the guys from xgm.guru (the russian modding community) for finding (back in 2007?) the method
// of attaching data to timers used by this library: http://xgm.guru/p/wc3/timer-exploit
//
// back in late 2006 Captain Griffen shows this method as well: http://www.wc3c.net/showpost.php?p=832021&postcount=3
//! novjass
// starting/creating a timer
//
static method start takes integer user_data, real timeout, code callback returns Timer
// stopping/releasing a timer
//
method stop takes nothing returns nothing
// pausing a timer
//
method pause takes nothing returns nothing
// there are two methods which give access to the data within the body of the callback function:
//
// the first is:
// Timer.get_expired_data, which is intended to be used by oneshot timers
//
// the second is:
// Timer.get_expired, which is intended to be used by periodic timers
//
// returns the data and automatically stops/releases the timer
//
static method get_expired_data takes nothing returns integer
// returns the timer instance which has the .data member with which you can access the data,
// but does NOT automatically stop/release the timer, i.e you have to do it manually (at some point)
//
static method get_expired takes nothing returns Timer
// this method needs to be called for periodic timers
// NOTE: the callback has to be passed again (because we can't store code variables in arrays, this is a Jass2 limitation)
//
method restart takes code callback returns nothing
//! endnovjass
struct Timer extends array
readonly static integer max_count = 0 // the maximum number of timers we've ever had ticking
readonly static integer curr_count = 0 // the current number of timers ticking
private static Timer head = 0 // a free list of timers
private Timer next
private timer t
integer data
real timeout
static method start takes integer user_data, real timeout, code callback returns Timer
local Timer this
if head != 0 then
set this = head
set head = head.next
else
set max_count = max_count + 1
if max_count > 8190 then
static if DEBUG_MODE then
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0.0, 0.0, 1000.0, "|cffFF0000[Timer] error: could not allocate a Timer instance|r")
endif
return 0
endif
set this = max_count
set this.t = CreateTimer()
endif
set curr_count = curr_count + 1
set this.next = 0
set this.data = user_data
set this.timeout = timeout
call TimerStart(this.t, this, false, null)
call PauseTimer(this.t)
call TimerStart(this.t, timeout, false, callback)
return this
endmethod
method stop takes nothing returns nothing
if this == 0 then
static if DEBUG_MODE then
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0.0, 0.0, 1000.0, "|cffFF0000[Timer] error: cannot stop null Timer instance|r")
endif
return
endif
if this.next != 0 then
static if DEBUG_MODE then
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0.0, 0.0, 1000.0, "|cffFF0000[Timer] error: cannot stop Timer(" + I2S(this) + ") instance more than once|r")
endif
return
endif
set curr_count = curr_count - 1
call TimerStart(this.t, 0.0, false, null)
set this.next = head
set head = this
endmethod
method pause takes nothing returns nothing
call TimerStart(this.t, 0.0, false, null)
endmethod
static method get_expired takes nothing returns Timer
return R2I(TimerGetRemaining(GetExpiredTimer()) + 0.5)
endmethod
static method get_expired_data takes nothing returns integer
local Timer t = Timer( R2I(TimerGetRemaining(GetExpiredTimer()) + 0.5) )
local integer data = t.data
call t.stop()
return data
endmethod
method restart takes code callback returns nothing
call TimerStart(this.t, this.data, false, null)
call PauseTimer(this.t)
call TimerStart(this.t, this.timeout, false, callback)
endmethod
endstruct
endlibrary
demo (worst demo ever):
JASS:
struct Message
string message
integer repeat_count
endstruct
function print_message takes nothing returns nothing
local Message msg = Timer.get_expired_data()
call BJDebugMsg(msg.message)
call msg.destroy()
endfunction
function print_message_once takes string message, real delay returns nothing
local Message msg = Message.create()
set msg.message = message
call Timer.start(msg, delay, function print_message)
endfunction
function print_message_many_times takes nothing returns nothing
local Timer t = Timer.get_expired()
local Message msg = t.data
call BJDebugMsg(msg.message + " (" + I2S(msg.repeat_count) + ")")
set msg.repeat_count = msg.repeat_count - 1
if msg.repeat_count > 0 then
call t.restart(function print_message_many_times)
else
call t.stop()
call msg.destroy()
endif
endfunction
function spam_message takes string message, real delay, integer repeat_count returns nothing
local Message msg = Message.create()
set msg.message = message
set msg.repeat_count = repeat_count
call Timer.start(msg, delay, function print_message_many_times)
endfunction
Last edited: