| 10-27-2008, 08:26 AM | #1 |
I made a thread about this here quite a while back, but it went off-topic and I didn't really want to revive it, hence this new one. The system's also undergone some changes since then. This system basically handles everything timer-related in the map with a single timer, allows any period for functions to be executed, and supports data-passing. It's like TT but has slightly different features and syntax. Besides general comments, I would greatly appreciate if anyone could help me spot bugs, if any. I recently came across a whole series of unpredictable, random bugs in a certain map I made. I spent days debugging to no avail and finally thought today to switch this system out with TimerUtils - the bugs went away. So, yeah - this system was seemingly what was causing the problems, even though it had worked without hitches in every map, test and scenario I had used it in thus far. I tested all the code again extensively in another map, and everything worked perfectly, like it always had before. ![]() Link to the original TH.net topic. JASS:library WaitSystem initializer Init //*************************************************************************** //* Wait System v1.3, by Darius34 //* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ //* [url]http://www.thehelper.net/forums/showthread.php?p=847782[/url] //* //* Essentially a way to rectify having to create and maintain multiple //* timers, replacing and running everything with a single one. Supports //* data-passing, and allows fully variable periods as low as 0.01 //* (by default) accurately. //* //* Function Usage/Syntax //* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ //* function Wait takes real duration, WS actionfunc, integer datastruct returns nothing //* //* - The main function. When calling it, the name of the user-defined //* function actionfunc has to be specified with the "WS." prefix. //* - actionfunc also has to take an integer (the data struct) and return //* a boolean. Returning true continues the periodic execution of the //* function, while returning false halts it. //* //* function GetWSExecCount takes nothing returns integer //* //* - This inline-friendly function keeps track of how many times a user- //* defined function has been executed by the system. It should only be used //* in said user-defined functions. //* //* Notes //* ¯¯¯¯¯ //* - The maxmimum accurate wait time/period you can have with this //* system is given by TIMER_PERIOD * ITERATION_LIMIT - 1000 seconds //* by default. //* - The 'wait' used here isn't like conventional wait; it doesn't pause //* execution. It runs like a normal timer would. //* //* - The period can be increased to the minimum period in the map. It's not //* advisable to change it, however, if you're using a large range of very //* low periods - a number that can't be divided by evenly (e.g. 0.03) //* could cause inaccuracies with timing. //* Leave the period as is if you're not sure how to change it. //* - This system is best used with multiple functions running at high //* frequency - it remains optimally efficient that way. A normal timer //* stack is more suited to only low-frequency executions. //* //* Credits //* ¯¯¯¯¯¯¯ //* - Vexorian and all the people who made vJass possible. //* - Cohadar for the concept behind TT, which I adapted some. //* //*************************************************************************** function interface WS takes integer DataStruct returns boolean private keyword waitdata globals // Configuration private constant boolean DISPLAY_ERROR_MESSAGES = true // Controls whether error messages are displayed. private constant real TIMER_PERIOD = 0.01 // The period of the universal timer. Can be increased to the minimum period in the map. // See documentation above for details on this. private constant integer ITERATION_LIMIT = 100000 // The number at which the counter used by the system resets. Just has to be large // enough so that the timer doesn't loop through and execute stuff a few cycles // earlier. Increase this if you need a wait longer than 1000 seconds. // -- System starts here. -- private timer Timer private integer IterationCount = 0 // Increments as the timer executes, resets when > ITERATION_LIMIT. private waitdata array WaitData private integer InstanceIndex = 0 // Index to be used for the next instance of execution. private integer array Stack // Contains recycled indices. private integer StackSize = 0 private integer ExecCount = 0 endglobals private struct waitdata WS ActionFunction integer RunCount integer DataStruct real Duration = 0 integer ExecutionCount = 1 endstruct function GetWSExecCount takes nothing returns integer return ExecCount // Inline-friendly! endfunction private function AllocateWaitIndex takes real duration, WS actionfunc, integer datastruct, waitdata tw returns nothing local integer actioncount local integer index local waitdata w // Determines count at which actions will be executed. if duration <= TIMER_PERIOD then set actioncount = IterationCount + 1 else set actioncount = R2I(duration/TIMER_PERIOD) + IterationCount endif if actioncount >= ITERATION_LIMIT then set actioncount = actioncount - ITERATION_LIMIT endif debug call BJDebugMsg(" Action Count: " + I2S(actioncount) + " | Iteration Count: " + I2S(IterationCount)) // Allocates the instance an index, prioritising freed slots. if StackSize > 0 then set StackSize = StackSize - 1 set index = Stack[StackSize] else set index = InstanceIndex set InstanceIndex = InstanceIndex + 1 endif debug call BJDebugMsg("Instance Index: " + I2S(index)) // Creates a data struct for a new wait instance or handles it for a subsequent, periodic wait. if tw == -1 then set w = waitdata.create() set w.ActionFunction = actionfunc set w.DataStruct = datastruct set w.Duration = duration else set w = tw set w.ExecutionCount = w.ExecutionCount + 1 endif set w.RunCount = actioncount set WaitData[index] = w endfunction function Wait takes real duration, WS actionfunc, integer datastruct returns nothing if actionfunc == 0 then if DISPLAY_ERROR_MESSAGES then call BJDebugMsg("Wait System - Error: No action function specified.") endif else call AllocateWaitIndex(duration, actionfunc, datastruct, -1) endif endfunction private function HandleIterations takes nothing returns nothing local integer a = 0 local waitdata w // Increments running count, resets it if necessary. set IterationCount = IterationCount + 1 if IterationCount > ITERATION_LIMIT then set IterationCount = 0 endif // Loops through arrays and checks counts, to see if any actions should be executed. loop exitwhen a > InstanceIndex set w = WaitData[a] if w.RunCount == IterationCount then set ExecCount = w.ExecutionCount if w.ActionFunction.evaluate(w.DataStruct) then call AllocateWaitIndex(w.Duration, w.ActionFunction, w.DataStruct, w) else call w.destroy() endif set Stack[StackSize] = a // Index recycling. set StackSize = StackSize + 1 endif set a = a + 1 endloop endfunction private function Init takes nothing returns nothing set Timer = CreateTimer() call TimerStart(Timer, TIMER_PERIOD, true, function HandleIterations) endfunction endlibrary |
| 10-27-2008, 09:01 AM | #2 |
JASS:private constant boolean DISPLAY_ERROR_MESSAGES = true JASS:function Wait takes real duration, WS actionfunc, integer datastruct returns nothing if actionfunc > 0 then // or actionfunc != 0 but I guess it wont go lower then 0. call AllocateWaitIndex(duration, actionfunc, datastruct, -1) debug else debug call BJDebugMsg("Wait System - Error: No action function specified.") endif endfunction This way it doesn't create a if then else and a if then statement. |
| 10-28-2008, 06:52 AM | #3 |
Okay, I'll change that (and remove the unneeded timer global - forgot it). |
| 10-31-2008, 04:46 AM | #4 |
Bump. Due to all the bugs, I'm actually planning to remake the system, and change the methods used slightly. So, yeah, I would really appreciate feedback. |
