| 11-17-2008, 05:18 PM | #1 | |
Quote:
I'm not sure what you've mean is exactly this kind of system, but I take the risk to show you this one I've made some times ago. It's purpose is to automatically handle timer/actions things, and let you place your actions inside the struct itself. It is very versatile and can be used as well for periodic than one-shot actions. I let you read a little more about it in the documentation below ;) Note: obviously, timers systems are fully compatible with this one, just replace TimerStart/DestroyTimer with your own functions. JASS://*************************************************************************************************** // StructTimers : // ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ // Version : 1.00 // Author(s) : profet // // // DESCRIPTION: // This system enables the user to link a struct to a timer, it handles timers' // expiration and automatically run the .End() method of the attached struct. // // // HOW TO USE? // Each struct that uses a timer must extend s_timer interface, each struct must // include 3 methods according to following prototypes: // _________ // .End() : Defines actions executed when the timer expires, also destroy the // ¯¯¯¯¯¯¯¯ structure's instance if it's return value is TRUE. // // /!\ Take care to potential timer and structure leaks when // returning FALSE if you don't destroy the struct by yourself. // // method End takes nothing returns boolean // return true // endmethod // // _______________ // .onDestroy() : Frees the timer when the struct is destroyed. // ¯¯¯¯¯¯¯¯¯¯¯¯¯¯ If you are using other structs inside the struct you can // destroy them here, but in most of cases you don't have to // modify this method, rather put your expiration actions in // .End() method. // // method onDestroy takes nothing returns nothing // call StructTimers_ReleaseTimerStruct(.ti) // endmethod // // ____________ // .create() : Creates a struct instance, initialize the timer and custom // ¯¯¯¯¯¯¯¯¯¯¯ struct's variables. // This method is with any doubt the less determinated of all, // and the prototype below is only a frame on which you must base // your own code. // // static method create takes <arguments list> returns <struct.name> // local <struct.name> this = <struct.name>.allocate() // set this.ti = CreateTimer() // call StructTimers_StartTimedStruct( this.ti, <real:timeout>, <boolean:periodic>, this ) // return this // endmethod // // // EXAMPLE: // The following example shows how to create a timer that checks every 0.5s if // the unit has a specific buff, and kills it if not. // // _____________________ // Structure definition // ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ // struct s_kill extends s_timer // private unit target // private integer buffid // private boolean explode // // method End takes nothing returns boolean // if( GetUnitAbilityLevel(.target,.buffid)==0 )then // call SetUnitExploded( .target, .explode ) // call KillUnit(.target) // return true // endif // return false // endmethod // // method ChangePeriod takes real newdelay returns nothing // call StructTimers_StartTimerStruct( this.ti, newdelay, true, this ) // endmethod // // method Stop takes nothing returns nothing // call .destroy() // endmethod // // method onDestroy takes nothing returns nothing // call StructTimers_ReleaseTimerStruct(.ti) // endmethod // // static method create takes unit un, boolean explode, integer buffid, real delay returns s_kill // local s_kill this = s_kill.allocate() // //Replace following line if you're using a timers system // set this.ti = CreateTimer() // //end of replace // set this.target = un // set this.explode = explode // set this.buffid = buffid // call StructTimers_StartTimerStruct( this.ti, delay, true, this ) // return this // endmethod // endstruct // // __________________________ // Structure's usage example // ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ // call s_kill.create( my_unit, false, 'BOac', 0.5 ) // // // //*************************************************************************************************** library StructTimers //=========================================================================== globals private integer STRUCT_TIMERS_COUNT = 0 private integer ASSOC_COUNT = 0 private timer array ASSOC_TIMER private i_timer array ASSOC_VALUE endglobals //=========================================================================== //INTERFACE DEFINITION: //All structs using timers MUST extend the following interface: interface i_timer timer ti = null method End takes nothing returns boolean endinterface //=========================================================================== //Searches for a timer in the associations-list, returns -1 if it isn't found. private function findTimer takes timer ti returns i_timer local integer i = 0 loop exitwhen( i==ASSOC_COUNT ) if( ASSOC_TIMER[i]==ti )then return i endif set i = i + 1 endloop return -1 endfunction //Removes an association from the list. private function removeTimerAssoc takes timer ti, integer index returns nothing if( index<0 )then set index = findTimer(ti) endif if( index>-1 )then set ASSOC_COUNT = ASSOC_COUNT - 1 set ASSOC_TIMER[index] = ASSOC_TIMER[ASSOC_COUNT] set ASSOC_VALUE[index] = ASSOC_VALUE[ASSOC_COUNT] endif endfunction //Create an association. private function setTimerAssoc takes timer ti, i_timer value returns boolean local integer index = findTimer(ti) if( index==-1 and value>0 )then set ASSOC_TIMER[ASSOC_COUNT] = ti set ASSOC_VALUE[ASSOC_COUNT] = value set ASSOC_COUNT = ASSOC_COUNT + 1 return true endif return false endfunction //Finds and returns an association, returns 0 if no association. private function getTimerAssoc takes timer ti returns i_timer local integer index = findTimer(ti) if( index>-1 )then return ASSOC_VALUE[index] endif return 0 endfunction //=========================================================================== //This function is executed when a struct-timer expires. Associated .end() method //is called, the struct is destructed if the method returns TRUE. private function timerExpiration takes nothing returns nothing local i_timer timerstruct = getTimerAssoc( GetExpiredTimer() ) if( timerstruct.End() )then call timerstruct.destroy() endif endfunction //=========================================================================== //Similar to the usual TimerStart function, except the fact it takes a 'structid' //argument, and does not need the <code:func> parameter. public function StartTimerStruct takes timer ti, real timeout, boolean periodic, integer structid returns boolean if( structid>0 and ti!=null and timeout>0. )then //Replace following line if you're using a timers system call TimerStart( ti, timeout, periodic, function timerExpiration ) //end of replace if( setTimerAssoc( ti, structid ) )then set STRUCT_TIMERS_COUNT = STRUCT_TIMERS_COUNT + 1 endif return true endif return false endfunction //Removes linked association (to keep the assoc-list as small as possible). public function ReleaseTimerStruct takes timer ti returns nothing if( ti!=null )then //Replace following lines if you're using a timers system call PauseTimer(ti) call DestroyTimer(ti) //end of replace call removeTimerAssoc(ti,-1) set STRUCT_TIMERS_COUNT = STRUCT_TIMERS_COUNT - 1 endif endfunction endlibrary |
| 11-17-2008, 06:35 PM | #2 |
I'm rather sure that cohadar was being sarcastic there, since attachment systems pretty much match timer systems in numbers. |
| 11-17-2008, 07:01 PM | #3 |
I was not sure.. Anyway, i'm just trying to share what I did and i hope someone could find it usefull ;) |
| 11-17-2008, 07:16 PM | #4 |
I just want to ask if the search function "findTimer" searches linearly? |
| 11-17-2008, 07:30 PM | #5 |
Yes, but since removeTimerAssoc doesn't leave free indexes, i think it doesn't really matter with the number of timers involved in a war3's map. Does it ? |
| 11-17-2008, 10:05 PM | #6 |
Depends on the map. |
| 11-19-2008, 03:21 AM | #7 |
I'm not so used to maths than you are, so could you explain what is the better search method I should use, and in wich specific cases use it ? |
| 11-19-2008, 06:51 AM | #8 |
O(n) searches are for all bar the smallest 'n's shit in almost all cases. |
| 11-19-2008, 01:17 PM | #9 |
Either use gamecache, or extended arrays like TimerUtils does. But your system is fairly limiting in that structs must extend a specific interface, often you may want to attach structs to timers that must extend a different interface. |
| 11-19-2008, 03:30 PM | #10 |
You could try using linked lists... I believe that would be the quickest way. |
| 11-19-2008, 11:11 PM | #11 | ||||||||||||||||
Quote:
Linked lists will not speed up linear searches. Worst Case Scenarios:
Linked lists are only good if you are constantly adding/removing items from places within the list (not the end only). Linear searches are horribly horrendous. |
| 11-20-2008, 04:48 AM | #12 |
that depends on how you use it, in jass there is really no linked list data structure, you just emulate it using arrays, so known index/address access can still be considered as O(1), but still if it's random accessing then you're right, you'll have to linearly search lol. Either use hashing (timerutils) or gamecahe(table). |
| 11-20-2008, 05:24 AM | #13 |
Linked lists can be emulated with locations or, better yet, structs. JASS:struct ListElement ListElement next dataType data endstruct The best approach would be the binary search, but it would require the list to be sorted to work, which then adds to the add/remove times. It really comes down to what you need it for. |
| 11-20-2008, 09:22 AM | #14 | |
I'll think to make a version using a different search method soon or later (maybe based on TimerUtils). This system is not designed especially for speed (but it could be very quick if I decide to base it on TU) or special cases that require the struct to be extended from an interface, but mainly for it's easy use. But I agree the fastest a system is, better it is ;) Quote:
I've done a lot of different systems and it has proved some kind of versatibility. |
