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

Timer System, Any suggestions?

Status
Not open for further replies.
Level 12
Joined
Aug 20, 2007
Messages
866
JASS:
//Dual Timer System v2.0
//
//Functions:
//
//TimedFunc(real time, integer struct, code func)
//
//*Executes code in a periodic manner, will not stop until the function returns true
//*If you want the code to stop in one-shot, simply put 'return true' at the bottom of the function <------------HOW TO USE
//
//Data()
//
//*Used in your functions that going to be called (func parameter), gets the struct you set when you called TimedFunc()
//
//Notes:
//
//Slower than using the single timer system
//
//======================================================================================================================
//
//Single Timer System v1.0
//
//~Documentation for the second half of the system which has been added~
//
//Functions:
//
//PeriodFunc(integer struct, code func)
//
//*A simple function that takes just a function and a struct, and it will execute it
//every .01 seconds, it will only stop executing when the function returns true <---------------HOW TO USE
//
//FastData()
//
//*Used in your functions, gets the struct you set when you called PeriodFunc()
//
//Notes:
//
//A high-speed method to call periodic functions, but at the cost
//of a changeable interval to call functions
//
//You can change the interval from .01 if you desire, the constant function 'Interval' in the SingleTimerSystem
//library is the number you can change
//
//This system can be very useful for other systems, such as knockback and physics, whereas the other timer system really
//shouldn't be used for very small repeating timeouts, although you can if you really want to
//
//*Faster than DTS
//
//======================================================================================================================
//
//Preloading:
//
//Both of these systems use preloading in order to speed up the systems in-game, which means it will automatically
//load a certain number of resources (currently set at 32) so that # of timed functions can be running at the same time
//without causing any problems. If you happen to exceed that limit with your map, this will not cause any serious problems,
//just a slow-down of the code due to in-game loading of necessary resources
//
//*The STS (SingleTimerSystem)'s Preload amount is only set at 16, because there really shouldn't be a hell of alot
//of functions running 100 times a second
//
//The Preload amounts can be set with the 'STSPreloadAmount' constant function, and the 'DTSPreloadAmount' constant function
//
//If your like many mappers(and gamers) out there, your going to want as little in-game preloading causing lag in your game
//I have provided some debug code to allow you to find the highest number of timedfunctions used during your game at any
//point (at the same time)
//
//In order to do so, simply enable the debug mode using JNGP, and test your map out online
//Obviously, your map will need to be finished
//
//In the global blocks at the beginning of each system, there is an integer 'N' which is used for debugging purposes
//If you have finished finding the appropriate Preload amount, you should remove that 'N'
//
//Please Note: Not having a high enough number of preloaded resources will not be enough to cause significant lag
//in-game. If your too lazy to set your Preload number accordingly to your map, this will not 'kill' your map, it will
//just cause a small amount of temporary lag that could've been avoided 

library SingleTimerSystem initializer STSPreLoad
globals
  private timer T = CreateTimer()
  prviate integer array Struct
  private integer Data
  private trigger array Function
  private trigger Swap
  //
  private integer N = 0 //This should be removed after you find the appropriate Preload amount
endglobals
private constant function STSPreloadAmount takes nothing returns integer
    return 16
endfunction
private constant function Interval takes nothing returns real
    return .01
endfunction
private function Working takes nothing returns nothing
    local integer i = 0
    loop
      exitwhen i == Max
      set Data = Struct[i]
      if TriggerEvaluate(Function[i]) then
        set Max = Max - 1
        set Swap = Function[i]
        set Function[i] = Function[Max]
        set Function[Max] = Swap
        set Struct[i] = Struct[Max]
        set i = i - 1
        if Max == 0 then
          call PauseTimer(T)
          return
        endif
      endif
      set i = i + 1
    endloop
endfunction
function PeriodFunc takes integer struct, code func returns nothing
    if Function[Max] == null then
      set Function[Max] = CreateTrigger()
      debug set N = N + 1
      debug call BJDebugMsg(" STSPRELOAD LIMIT REACHED, CURRENT RESOURCES: " + I2S(N+STSPreloadAmount()))
    endif
    call TriggerClearConditions(Function[Max])
    call TriggerAddCondition(Function[Max], Condition(func))
    set Struct[Max] = struct
    set Max = Max + 1
    if Max == 1 then
      call TimerStart(T, Interval(), true, function Working)
    endif
endfunction
constant function FastData takes nothing returns integer
    return Data
endfunction
function STSPreLoad takes nothing returns nothing
    local integer i = 0
    loop
      exitwhen i > STSPreloadAmount()
      set Function[i] = CreateTrigger()
      set i = i + 1
    endloop
endfunction
endlibrary

library DualTimerSystem initializer DTSPreLoad
globals
  private timer T = CreateTimer()
  private real array Working
  private real array TimeOut
  private real TimerTimeOut = 0.0
  private integer array Struct
  private integer Data
  private trigger array Function
  private trigger Swap
  //
  private integer N = 0 //This should be removed after you find the appropriate Preload amount
endglobals
private constant function DTSPreloadAmount takes nothing returns integer
    return 32
endfunction
private constant function MaxTimeOut takes nothing returns real
    return 20000.0
endfunction
//This is a constant function for the largest number of seconds you can put into one
//timed function
//This number isn't too important, its just how the system is set-up
//If you feel you need more than 5 hours in a single timer, you can change this number as you please
//Although, for very long timeouts, I do suggest using QUICK_TIMER()
private function Working takes nothing returns nothing
    local integer i = 0
    local real newtimeout = MaxTimeOut()
    loop
      exitwhen i == Max
      set Working[i] = Working[i] - TimerTimeOut
      if Working[i] == 0 then
        set Working[i] = TimeOut[i]
        set Data = Struct[i]
        if TriggerEvaluate(Function[i]) then
          set Max = Max - 1
          set Working[i] = Working[Max]
          set TimeOut[i] = TimeOut[Max]
          set Struct[i] = Struct[Max]
          set Swap = Function[i]
          set Function[i] = Function[Max]
          set Function[Max] = Swap
          set i = i - 1
        endif
        else
          if Working[i] < newtimeout then
            set newtimeout = Working[i]
          endif
      endif
      set i = i + 1
    endloop
    set TimerTimeOut = newtimeout
    call TimerStart(T, newtimeout, false, function Working)
    if Max == 0 then
      call PauseTimer(T)
    endif
endfunction
function TimedFunc takes real time, integer struct, code func returns nothing
    local integer i = 0
    local real TimeElapsed = TimerGetElapsed(T)
    call PauseTimer(T)
    set TimerTimeOut = time
    loop
      exitwhen i == Max
      set Working[i] = Working[i] - TimeElapsed
      if Working[i] < TimerTimeOut then
        set TimerTimeOut = Working[i]
      endif
      set i = i + 1
    endloop
    if Function[Max] == null then
      set Function[Max] = CreateTrigger()
      debug set N = N + 1
      debug call BJDebugMsg("DTSPRELOAD LIMIT REACHED, CURRENT RESOURCES: " + I2S(N+STSPreloadAmount()))
    endif
    call TriggerClearConditions(Function[Max])
    call TriggerAddCondition(Function[Max], Condition(func))
    set Struct[Max] = struct
    set Working[Max] = time
    set TimeOut[Max] = time
    call TimerStart(T, TimerTimeOut, false, function Working)
    set Max = Max + 1
endfunction
constant function Data takes nothing returns integer
    return Data
endfunction
function DTSPreLoad takes nothing returns nothing
    local integer i = 0
    loop
      exitwhen i > DTSPreloadAmount()
      set Function[i] = CreateTrigger()
      set i = i + 1
    endloop
endfunction
endlibrary
 
Last edited:
Level 15
Joined
Feb 15, 2006
Messages
851
An impressive amount of code to do something that a native function does...

TimerStart(NewTimer(), value, periodic?, function your_code)

This one doesn't load any trigger, and you set before if you want it periodic or not...

And if you need to attach a struct, just use timerutils' function SetTimerData(timer, integer_Value)

timerutils link: http://www.wc3campaigns.net/showthread.php?t=101322
 
Level 12
Joined
Apr 27, 2008
Messages
1,228
An impressive amount of code to do something that a native function does...

TimerStart(NewTimer(), value, periodic?, function your_code)

This one doesn't load any trigger, and you set before if you want it periodic or not...

And if you need to attach a struct, just use timerutils' function SetTimerData(timer, integer_Value)

timerutils link: TimerUtils (Blue and Red) - Wc3campaigns

What, you blind? Don't know English? Have problems reading?
The whole Idea is to use 1 timer. If you do not understand something, do not comment against it.
 
Level 15
Joined
Feb 15, 2006
Messages
851
What, you blind? Don't know English? Have problems reading?
The whole Idea is to use 1 timer. If you do not understand something, do not comment against it.
Waht we got here? a clever dude... let me clarify something: I check first if the code is useful, then if it's properly coded, besides, if the purpose of this whole system is simply using one timer, then the author has failed double.

This code pretends to change the horrible approach of having several timers running different codes by setting one timer that controls an array of triggers (because we can code to a trigger). If we look closely, we are just changing the timers with triggers, with the difference that if we have n handles activated, this system will have n + 1 (n triggers + the timer that controls them). And do the same.... LIE!!! they don't, the timers approach allow me to have different periods and the other only a fixed period value... what a shit... And I don't mention the possibility of recycle timers because you're too smart to get it.

Now, to end this boring discussion, I want to notice this:

[jass=Extract from this code]private function Working takes nothing returns nothing
local integer i = 0
loop
exitwhen i == Max
set Data = Struct
if TriggerEvaluate(Function) then
set Max = Max - 1
set Swap = Function
set Function = Function[Max]
set Function[Max] = Swap
set Struct = Struct[Max]
set i = i - 1
if Max == 0 then
call PauseTimer(T)
return
endif
endif
set i = i + 1
endloop
endfunction[/code][c][jass=Extract from TT timer ticker system by cohadar]private function Handler takes nothing returns nothing
local trigger swap
local integer i = Counter
loop
exitwhen i<=0
set Data = Dataz
if TriggerEvaluate(Triggz) then
set swap = Triggz
call TriggerClearConditions(swap)
set Triggz = Triggz[Counter]
set Triggz[Counter] = swap
set Dataz = Dataz[Counter]
set Counter = Counter - 1
endif
set i = i - 1
endloop
// who can guess why am I not nulling swap here?
endfunction[/code]
Link: TT - Timer Ticker system - Wc3campaigns


And there are more similarities. Well, I'm not against to learn and take code ideas to develop your own stuff, but doing this to do the same thing?? definitely we're failing here. Dr Super Good's post has been justified. This is practically a variation of TT, but with more lines of code and definitely less efficient.

Ok, I'm tired, and please don't expect any other answer from me, dealing with "smart guys" like you make me feel sick.
 
Last edited:
Level 12
Joined
Apr 27, 2008
Messages
1,228
Congrats. You read the code.

Using a lot of timers at the same time will cause ... lag.
Clearing and adding conditions to a trigger is safer than creating and destroying handles. I am uncertain about
the speed difference, but in TT it is clearly stated this method is faster than attaching to handles.
Both this system and TT allow different timeouts, but the timer thick, in TT and the first part of this system is fixed.
Difference between TT and this, is that with TT in each "callback" function you would have to code a way to check
if it is the right time to execute it. And here, that is done by the system.

My request remains the same: Do not comment against something before you understand it.
 
Level 12
Joined
Aug 20, 2007
Messages
866
Thank you spiwn, you understand it :)

Yes, moyack the first system is pretty much a copy of the TT system, the second system is really whats special. The reason I included both, is because they have different purposes. The TT version is for heavy systems, such as physics. The second system, is for when you want a specific timeout. The reason I don't use timerutils, is because I don't know how fast it is, and I'm suspicious this could be quicker.

EDIT - The second version is really an alteration of the original TT concept. I also was not sure whether or not you get a boost on speed if you use pre-loaded triggers. I'm not sure whether creating a handle uses more memory/speed than the actual existance of the handle. I do know, that during run-time there is a legitimate increase in speed when using a preloaded trigger system rather than attaching the code to a newly created trigger and then destroying it every timeout.
 
Last edited:
Level 15
Joined
Feb 15, 2006
Messages
851
Thank you spiwn, you understand it :)

Yes, moyack the first system is pretty much a copy of the TT system, the second system is really whats special. The reason I included both, is because they have different purposes. The TT version is for heavy systems, such as physics. The second system, is for when you want a specific timeout. The reason I don't use timerutils, is because I don't know how fast it is, and I'm suspicious this could be quicker.

EDIT - The second version is really an alteration of the original TT concept. I also was not sure whether or not you get a boost on speed if you use pre-loaded triggers. I'm not sure whether creating a handle uses more memory/speed than the actual existance of the handle. I do know, that during run-time there is a legitimate increase in speed when using a preloaded trigger system rather than attaching the code to a newly created trigger and then destroying it every timeout.
Preloading triggers doesn't improve speed in general, just helps to avoid the famous first time lag or such. what is sure is that creating handles increases the memory consumption and this is a performance factor that is as important (or more in some cases) than speed.

Hmmm... well, when I knew TT the first time, the idea of having a single timer handling all the periodic events in a game sounds tempting and logical, In fact my project used that principle and I was happy for that, but when you load and load functions to that system, you will have the same effect: a lovely periodic lag but now with the triggers, why? because the sum of all these functions running at the same time. How do I solved this? distributing this into several timers hopefully not syncronized, one timer per system or spell code...

Now let's think about this: Why are we using triggers? why do they have to be triggers? just because we want to enter as a parameter a function? let me tell you something, cohadar uses triggers practically for that reason, not for performance... I tested with ExecuteFunc in a projectile system and I was able to keep more than 120 units moving with no lag... so this is a good option to test.

Now other question: can we add to a trigger a code as parameter directly? no, actually we need to create a trigger and a triggercondition or triggeraction linked to it to achieve this. So your system is not only creating triggers that are not destroyed but you have to add them a triggercondition, so your system creates 2n + 1 handles compared to have n timers running periodically.

What's the approach I suggest? recycle timers. Recycling implies that the game only creates the timers that are really needed, if one is unused and the game needs to use one of them, it just pick that unused timer saving loading time and memory.

As a resume: we as code developers should avoid to create needs to justify our coding skills, cohadar is a guy that tends to do this very commonly, and TT is a sample of this.

I hope this helps you :)
 
Level 12
Joined
Apr 27, 2008
Messages
1,228
I agree, using 1 timer in the whole map is not a good idea. How to distribute the load over several timers is a matter of personal opinion.
The Execute approach is the one of my choice too.
Only problem with execute is getting the string correct ^^
I think trigger evaluate is faster than execute, but that is does not account for clearing and adding conditions.
P.s. @moyack: now that is constructive feedback :)

This is not a copy of TT, this began here.
 
Level 12
Joined
Aug 20, 2007
Messages
866
Yeah, these are the problems I considered during development

I haven't tested the system nor any of the variations using triggers vs. strings

The thing to remember is that not all handles are the same size, and it doesn't come out to 2n + 1. I don't know how much memory the triggers and conditions take, but the increase in speed for periodic functions in calling evaluate rather than execute is more valuable to me.

The clearing and adding of conditions occurs when you call the function.

moyack, you missed one piece of the equation. The real reason I made this is not for the handle count, but for the attachment system. Every other attachment system that exists slows down the periodic code they run by using some kind of store + return integer system for structs.

Using it this way incorporates the integer so that you gain speed on not using an attachment system. I personally hate most attachment systems, my favorite so far would be cohadar's hash system, which reduces the function to simple math functions, but still relies on a bug, and calls a function, however small, for that bug.

The fact that this only uses one timer is more of an added benefit than a sole purpose.

I will try to find out how much memory the handles use, and whether or not using triggers is worth it.
 
Level 14
Joined
Nov 20, 2005
Messages
1,156
"//This is the 2nd fastest way to call timed functions. The only way to call them faster would be to use the
//SingleTimerSystem, which is sometimes inappropriate, because it can only run at one pre-set interval"

I call bull. Benchmarks or no deal, buster. Benchmark this against TimerUtils red (which, incidentally, still isn't the second fastest way). TimerUtils WILL beat this by a pretty considerably amount without attaching, and probably with it, too.

"//I believe this is the fastest possible way to call periodic functions, but at the cost
//of a changeable interval to call functions"

Bollocks. Before you make such claims, research, boy. WC3Campaigns is generally the best place to start. Rapid Timers is faster than TT by ~30%, and you can probably for most applications make something faster than that (but not with a generic system, but by embedding).

Oh, and, really, could you rip TT off any more with your code for that? It's absolutely identicle. You have nothing new at all; nor is your 'dual timer' system - the name of which seems to be outdated, since you only have one timer in it (whereas whichever implementation you ripped off had two)?
 
Level 12
Joined
Aug 20, 2007
Messages
866
I call it dual because its a package, two systems that work using one timer each. I was a bit lazy to think up a better name, sue me. Yes, you could say that the first system was ripped off, I had thought it up late, so technically ripped off.

The second I think could also be considered ripped off, although you'll have trouble finding it, because I had tried over and over to find a timer system using the same concept.

So your opinion is scrap it and look more towards timerutils & rapidtimers?

On a side note - You could let me know without calling me 'boy', I find it rather insulting
 
Level 14
Joined
Nov 20, 2005
Messages
1,156
I call it dual because its a package, two systems that work using one timer each. I was a bit lazy to think up a better name, sue me. Yes, you could say that the first system was ripped off, I had thought it up late, so technically ripped off.

The second I think could also be considered ripped off, although you'll have trouble finding it, because I had tried over and over to find a timer system using the same concept.

Yes, it is ripped off. And no, I wouldn't. Took me a few minutes.

So your opinion is scrap it and look more towards timerutils & rapidtimers?

99% of the time you want TU. The other 1% of the time you're likely better served by specific code optimisation and inlining, rather than any systems.

On a side note - You could let me know without calling me 'boy', I find it rather insulting

What I find insulting is your claims that your system is better without even the most basic of benchmarking or research.
 
Level 12
Joined
Aug 20, 2007
Messages
866
I'll delete those lines as so not to cause confusion, and not insult anybody. I I should've provided feasible data on what systems work best.

Ok, I'll look into TimerUtils, I don't particularly like reading Vexorians code, as much as I hate to admit it, he is far more intelligent than I am, and his code takes me time to understand.

EDIT - I took a look at TimerUtils, apparantly, its just a combination of a timer data system and a timer recycling system. I don't know whether or not that is faster than this, again I need to do research, but I don't think it is safe to say TimerUtils is the fastest way to run timed functions.
 
Last edited:
Level 15
Joined
Feb 15, 2006
Messages
851
EDIT - I took a look at TimerUtils, apparantly, its just a combination of a timer data system and a timer recycling system. I don't know whether or not that is faster than this, again I need to do research, but I don't think it is safe to say TimerUtils is the fastest way to run timed functions.
Could you please explain why you think that timerutils is not the fastest way??
 
Status
Not open for further replies.
Top