Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*----------------------------------------------------------------------------*\
- ====================================
- y_timers - Run timers efficiently.
- ====================================
- Description:
- Sets up repeating timers without requiring any SetTimers and arranges them
- so that they will be very unlikely to meet (at least for a long time) using
- scheduling algorithms to get timers with the same period to be offset. Also
- fixes arrays and strings in timers so they can be passed properly.
- Legal:
- Version: MPL 1.1
- The contents of this file are subject to the Mozilla Public License Version
- 1.1 (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
- http://www.mozilla.org/MPL/
- Software distributed under the License is distributed on an "AS IS" basis,
- WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- for the specific language governing rights and limitations under the
- License.
- The Original Code is the YSI timers include.
- The Initial Developer of the Original Code is Alex "Y_Less" Cole.
- Portions created by the Initial Developer are Copyright (C) 2011
- the Initial Developer. All Rights Reserved.
- Contributors:
- ZeeX, koolk, JoeBullet/Google63, g_aSlice/Slice
- Thanks:
- JoeBullet/Google63 - Handy arbitrary ASM jump code using SCTRL.
- ZeeX - Very productive conversations.
- koolk - IsPlayerinAreaEx code.
- TheAlpha - Danish translation.
- breadfish - German translation.
- Fireburn - Dutch translation.
- yom - French translation.
- 50p - Polish translation.
- Zamaroht - Spanish translation.
- Dracoblue, sintax, mabako, Xtreme, other coders - Producing other modes
- for me to strive to better.
- Pixels^ - Running XScripters where the idea was born.
- Matite - Pestering me to release it and using it.
- Very special thanks to:
- Thiadmer - PAWN, whose limits continue to amaze me!
- Kye/Kalcor - SA:MP.
- SA:MP Team past, present and future - SA:MP.
- Version:
- 2.0
- Changelog:
- 29/04/11:
- Added version 2 of the code with more advanced options.
- 21/03/11:
- Added debug printing to timer functions. Uses "P:C" in compiling.
- 26/10/10:
- Officially added simple calling.
- Added "delay" functions.
- 12/10/10:
- Rewrote for YSI 1.0 using y_scripting.
- 11/08/07:
- Removed millions of defines to reduce pre-processing.
- Added pickups.
- 03/08/07:
- First version.
- \*----------------------------------------------------------------------------*/
- // Disable this version!
- #if defined USE_Y_TIMERS_V1
- #include <YSI\internal\y_version>
- #include <YSI\internal\y_shortfunc>
- #include <YSI\y_hooks>
- #include <YSI\y_amx>
- #include <YSI\y_debug>
- //#define Timer:%0[%1](%2) forward @yT_%1_%0();@yT_%1_%0()
- #define Timer:%0[%1](%2) @yT_%1_%0();stock %0()@yT_%1_%0();@yT_%1_%0()P:C(for(new __%0=1;__%0&&(printf("Timer "#%0"["#%1"]" called.")|1);__%0^=1));
- #define Delay:%0[%1,%2](%3) stock %0(%3)return O@(#@#%0,%1,0,#%2#x,%3);stock v@%0(_:_o@,%3)return O@(#@#%0,_o@,0,#%2#x,%3);@%0(%3);@%0(%3)
- #define FixDelay:%0[%1,%2](%3) stock %0(%3)return O@("@_"#%0,%1,0,#%2#x,%3);@_%0(%3);@_%0(%3)
- // There's a bug in passing strings to timer functions, so I've remove it.
- //#define Delay@p:%0[%1,%2](%3)<%4> stock %0(%3)return O@(#@#%0,%1,0,#%2,%4);stock v@%0(_o@,%3)return O@(#@#%0,_o@,0,#%2,%4);forward @%0(%3);@%0(%3)
- #define skip:%0(%3) @%0(%3)
- #define delay:%0[%1](%3) v@%0(_:%1,%3)
- // This defines the number of different periods that timers can have. This
- // number is a HUGE over-estimate, you would need to have over 256 timers, none
- // of them with the same period, for this number to be too small!
- #define MAX_TIMER_VARIATIONS (256)
- //#define timer%0[%1](%2) %0@yT_();public%0@yT_()
- forward Timer_Start(timer, delay);
- /*----------------------------------------------------------------------------*\
- Function:
- OnScriptInit
- Params:
- -
- Return:
- -
- Notes:
- -
- \*----------------------------------------------------------------------------*/
- hook OnScriptInit()
- {
- new
- buffer[32],
- idx = 0,
- timers[MAX_TIMER_VARIATIONS][2],//[3],
- periods = 0;
- // 0 = time, 1 = count, 2 = offset.
- // First loop - get all the different periods.
- // Get the list of timers from the list of publics.
- while ((idx = AMX_GetPublicNamePrefix(idx, buffer, _A<@yT_>)))
- {
- // Get the time associated with the timer. We know this starts at index
- // position 4, because we always set it to be there.
- new
- time = strval(buffer[1]);
- if (time)
- {
- // Valid time, find this in the array.
- for (new i = 0; ; ++i)
- {
- if (i == periods)
- {
- timers[i][0] = time;
- timers[i][1] = 1;
- ++periods;
- break;
- }
- else if (timers[i][0] == time)
- {
- ++timers[i][1];
- break;
- }
- }
- if (periods == MAX_TIMER_VARIATIONS)
- {
- P:E("Timer array full");
- break;
- }
- }
- }
- // Group timers with common periods together, for example timers with 1000
- // and 500ms periods need to be interleaved so they don't run at the same
- // time very often. Obviously ANY combination of timers will eventually run
- // at the same time at some point, but we can reduce this chance.
- /*for (new i = 0; i != periods; ++i)
- {
- new
- time = timers[i][0];
- if (timers[i][2])
- {
- for (new j = 0; j != i; ++j)
- {
- new
- ct = timers[j][0];
- if ((time / ct) * ct == time || (ct / time) * time == ct)
- {
- // Set the count to the same as the master.
- timers[i][1] = timers[j][1];
- break;
- }
- }
- }
- else
- {
- new
- offset = timers[i][1];
- for (new j = i + 1; j != periods; ++j)
- {
- // Find similar periods.
- new
- ct = timers[j][0];
- if ((time / ct) * ct == time)
- {
- // This time is larger.
- }
- else if ((ct / time) * time == ct)
- {
- }
- if ((time / ct) * ct == time || (ct / time) * time == ct)
- {
- // That's integer division, so valid code. Mark this
- // element as controlled by another element.
- timers[j][2] = offset;
- offset += timers[j][1];
- }
- }
- timers[i][1] = offset;
- }
- }*/
- printf("ENTRY>>>>");
- C:1(for(new i;i!=periods;++i)printf("%d %d %d",timers[i][0],timers[i][1],0););//,timers[i][2]););
- // Now we know how many of each period there are we can try arrange them so
- // that they execute at very different times.
- // [1] contains the total number of timers on similar periods.
- for (new i = 0; i != periods; ++i)
- {
- // First calculate the gap between the timers.
- new
- time = timers[i][0],
- offset = time / timers[i][1];
- // Now start all the timers with this time at that offset.
- idx = 0;
- new
- last = 0,
- curo = offset;
- while ((idx = AMX_GetPublicNamePrefix(idx, buffer, _A<@yT_>)))
- {
- if (strval(buffer[1]) == time)
- {
- // That's the old start code, which uses 7ms offsets to try get
- // as close as possible to different server frames (5ms).
- SetTimerEx("Timer_Start", curo + (random(14) - 7), 0, "ii", last, time);
- //SetTimerEx("Timer_Start", curo, 0, "ii", last, time);
- curo += offset;
- }
- // So that the first found timer in the next function is correct.
- last = idx;
- }
- }
- }
- /*----------------------------------------------------------------------------*\
- Function:
- Timer_Start
- Params:
- timer - Approximate public function index.
- delay - How often it's called.
- Return:
- -
- Notes:
- Only needed for more than one timer. Offsets calls from each other for
- better server load distribution.
- \*----------------------------------------------------------------------------*/
- public Timer_Start(timer, delay)
- {
- new
- buffer[32];
- AMX_GetPublicNamePrefix(timer, buffer, _A<@yT_>);
- SetTimer(buffer, delay, 1);
- }
- #else
- /*============================================================================*\
- *==============================================================================*
- ================================================================================
- |||| ||||
- |||| HERE BEGINS VERSION 2! ||||
- |||| ||||
- ================================================================================
- *==============================================================================*
- \*============================================================================*/
- #include <YSI\internal\y_version>
- #include <YSI\y_amx>
- #include <YSI\internal\y_shortfunc>
- #include <YSI\y_malloc>
- #include <YSI\y_iterate>
- // This will be called twice and means there are two separate OnScriptInit
- // functions in this file.
- #include <YSI\y_hooks>
- #include <YSI\y_debug>
- #define task%0[%1](%2) %0@yT_(g,p);public%0@yT_(g,p){static s=-1;return _Timer_I(#%0,%1,g,s);}%0();public%0()
- #define ptask%0[%1](%2) stock %0_yT@=1;%0@yT_(g,p);public%0@yT_(g,p){static s[MAX_PLAYERS]={-1,...},a[2];return _Timer_D(#%0@_yT,%1,g,p,s,%0_yT@,a);}%0@_yT(p);public%0@_yT(p)if(%0_yT@)%0(p);%0(%2)
- #define pause%0; {J@=_:@Ym:%0@yT_(0,-1);}
- #define resume%0; {J@=_:@Ym:%0@yT_(1,-1);}
- #define @Ym:%0:%1@yT_(%2,-1) %0@yT_(%2,%1)
- static stock
- Alloc:YSI_g_sLastSlot = NO_ALLOC,
- Alloc:YSI_g_sFirstSlot = NO_ALLOC,
- YSI_g_sPlayerTimers = -1;
- hook OnScriptInit()
- {
- P:1("hook Timers_OnScriptInit called");
- new
- pointer,
- time,
- idx,
- entry;
- while ((idx = AMX_GetPublicEntrySuffix(idx, entry, _A<@yT_>)))
- //while ((idx = AMX_GetPublicPointerSuffix(idx, pointer, _A<@yT_>)))
- {
- P:6("Timer_OnScriptInit: entry: %d", entry);
- #emit LREF.S.pri entry
- #emit STOR.S.pri pointer
- //YSI_g_sCurFunc = pointer;
- // Don't bother with the real name, call the function by address to get
- // the time the function runs for.
- P:7("Timer_OnScriptInit: pointer: %d", pointer);
- // Push the address of the current function.
- #emit PUSH.S pointer
- #emit PUSH.C 0xFFFFFFFF
- #emit PUSH.C 8
- #emit LCTRL 6
- #emit ADD.C 28
- #emit PUSH.pri
- #emit LOAD.S.pri pointer
- #emit SCTRL 6
- #emit STOR.S.pri time
- //YSI_g_sCurFunc = 0;
- P:7("Timer_OnScriptInit: time: %d", time);
- if (time != -1)
- {
- // Find all the functions with the same time. This is less
- // efficient than previous implementations (it is O(N^2)), but also
- // more robust as it won't fail no matter how many different times
- // there are - old ones relied on an array with a finite size.
- new
- pointer2,
- time2,
- idx2,
- total,
- pre;
- while ((idx2 = AMX_GetPublicPointerSuffix(idx2, pointer2, _A<@yT_>)))
- {
- // Call the functions a second time to guarantee getting
- #emit PUSH.C 0
- #emit PUSH.C 0xFFFFFFFF
- #emit PUSH.C 8
- #emit LCTRL 6
- #emit ADD.C 28
- #emit PUSH.pri
- #emit LOAD.S.pri pointer2
- #emit SCTRL 6
- #emit STOR.S.pri time2
- if (time2 == time)
- {
- ++total;
- if (idx2 < idx)
- {
- ++pre;
- }
- }
- }
- P:7("Timer_OnScriptInit: total: %d, time: %d, pre: %d", total, time, pre);
- // Now we know what time this function has, how many others have
- // that time and how many have already been started.
- new
- buffer[32];
- entry += 4;
- #emit LREF.S.pri entry
- #emit STOR.S.pri pointer
- AMX_ReadString(AMX_BASE_ADDRESS + pointer, buffer);
- P:7("Timer_OnScriptInit: %s", unpack(buffer));
- // Get the time offset for the current call. This should mean that
- // all the functions are nicely spread out.
- SetTimerEx(buffer, time * pre / total, 0, "ii", 1, -1);
- }
- }
- P:1("hook Timers_OnScriptInit ended");
- }
- hook OnPlayerConnect(playerid)
- {
- P:1("hook Timers_OnPlayerConnect called: %d", playerid);
- // Loop through all the per-player timers. Correctly finds them all from a
- // linked list hidden in static variables (which are really global).
- new
- cur = YSI_g_sPlayerTimers,
- data;
- while (cur != -1)
- {
- #emit LREF.S.pri cur
- #emit STOR.S.pri data
- P:6("Timers_OnPlayerConnect: func: %x", data);
- // Start this timer for this player.
- #emit PUSH.S playerid
- #emit PUSH.C 1
- // Push the parameter count (in bytes). This is actually passed to
- // native functions directly.
- #emit PUSH.C 8
- // Call the function currently in the list to trigger the repeating
- // timer. This involves getting the current "cip" address, modifying it
- // to get the return address then modifying "cip" to call the function.
- #emit LCTRL 6
- #emit ADD.C 28
- #emit PUSH.pri
- #emit LOAD.S.pri data
- #emit SCTRL 6
- // Returned, get the next list element.
- cur += 4;
- #emit LREF.S.pri cur
- #emit STOR.S.pri cur
- }
- P:1("hook Timers_OnPlayerConnect ended");
- }
- hook OnPlayerDisconnect(playerid, reason)
- {
- P:1("hook Timers_OnPlayerDisconnect called: %d, %d, playerid, reason");
- // Loop through all the per-player timers. Correctly finds them all from a
- // linked list hidden in static variables (which are really global).
- new
- cur = YSI_g_sPlayerTimers,
- data;
- while (cur != -1)
- {
- #emit LREF.S.pri cur
- #emit STOR.S.pri data
- P:6("Timers_OnPlayerDisconnect: func: %x", data);
- // End this timer for this player.
- #emit PUSH.S playerid
- #emit PUSH.C 0
- // Push the parameter count (in bytes). This is actually passed to
- // native functions directly.
- #emit PUSH.C 8
- // Call the function currently in the list to trigger the repeating
- // timer. This involves getting the current "cip" address, modifying it
- // to get the return address then modifying "cip" to call the function.
- #emit LCTRL 6
- #emit ADD.C 28
- #emit PUSH.pri
- #emit LOAD.S.pri data
- #emit SCTRL 6
- // Returned, get the next list element.
- cur += 4;
- #emit LREF.S.pri cur
- #emit STOR.S.pri cur
- }
- P:1("hook Timers_OnPlayerDisconnect ended");
- }
- stock _Timer_I(func[], interval, action, &result)
- {
- P:3("_Timer_I called");
- switch (action)
- {
- case 0:
- {
- if (result != -1)
- {
- KillTimer(result),
- result =- 1;
- }
- }
- case 1:
- {
- if (result == -1)
- {
- result = SetTimer(func, interval, 1);
- }
- }
- }
- return interval;
- }
- // Attempt to stop or start a task, possibly for a single player.
- stock _Timer_D(func[], interval, const action, who, results[MAX_PLAYERS], &pause, a[2])
- {
- P:3("_Timer_D called");
- switch (action)
- {
- case -1:
- {
- if (who)
- {
- a[0] = who;
- a[1] = YSI_g_sPlayerTimers;
- // Store the address of the global array.
- #emit LOAD.S.pri a
- #emit STOR.pri YSI_g_sPlayerTimers
- }
- }
- case 0:
- {
- // Stop the timer.
- if (who == -1)
- {
- pause = 0;
- }
- else if (results[who] != -1)
- {
- KillTimer(results[who]);
- results[who] = -1;
- }
- }
- case 1:
- {
- // Start the timer.
- if (who == -1)
- {
- pause = 1;
- }
- else if (results[who] == -1)
- {
- results[who] = SetTimerEx(func, interval, true, "i", who);
- }
- }
- }
- // No global interval for per-player timers.
- return -1;
- }
- static stock Alloc:Timer_GetSingleSlot(len)
- {
- // Allocates memory and secretly appends data to the start.
- P:4("Timer_GetSingleSlot called: %d", len);
- new
- Alloc:slot = malloc(len + 1);
- if (slot == NO_ALLOC)
- {
- return NO_ALLOC;
- }
- P:5("Timer_GetSingleSlot: %d, %d, %d", _:YSI_g_sFirstSlot, _:YSI_g_sLastSlot, _:slot);
- // Standard linked list.
- if (YSI_g_sFirstSlot == NO_ALLOC)
- {
- YSI_g_sFirstSlot = slot;
- }
- else
- {
- mset(YSI_g_sLastSlot, 0, _:slot);
- }
- YSI_g_sLastSlot = slot;
- mset(YSI_g_sLastSlot, 0, -1);
- return slot;// + Alloc:1;
- }
- // Allocate memory to store a string.
- stock _Timer_S(string:str[])
- {
- P:3("_Timer_S called");
- new
- len = strlen(str);
- if (len & 0x0F)
- {
- len = (len & ~0x0F) + 32;
- }
- new
- Alloc:slot = Timer_GetSingleSlot(len + 1);
- if (slot != NO_ALLOC)
- {
- msets(slot, 1, str);
- }
- P:5("str: %d", _:slot);
- return _:slot + 1;
- }
- // Allocate memory to store an array.
- stock _Timer_A(str[], len)
- {
- P:3("_Timer_A called");
- new
- Alloc:slot = Timer_GetSingleSlot(len);
- if (slot != NO_ALLOC)
- {
- mseta(slot, 1, str, len);
- }
- P:5("str: %d", _:slot);
- return _:slot + 1;
- }
- stock
- I@ = -1;
- // Create the timer setup.
- stock _Timer_C(timer, g)
- {
- P:3("_Timer_C called: %d, %d", timer, g);
- //P:3("_Timer_C called: %d", timer);
- // This is done here for convenience.
- I@ = -1;
- // Only repeating timers are freed like this.
- // UPDATE: Now all timers with array parameters, regardless of repeat status
- // are freed like this. Only timers with no malloc aren't.
- if (g)
- {
- new
- Alloc:slot = Timer_GetSingleSlot(1);
- P:5("_Timer_C: slot = %d", _:slot);
- if (slot == NO_ALLOC)
- {
- // Not a graceful fail!
- return 0;
- }
- mset(slot, 1, timer);
- // Just so it isn't a real timer ID (or possibly isn't).
- slot = ~YSI_g_sFirstSlot;// ^ Alloc:-1;
- YSI_g_sFirstSlot = NO_ALLOC;
- YSI_g_sLastSlot = NO_ALLOC;
- return _:slot;
- }
- // Reset these variables on all timers, including self-cleaning ones.
- YSI_g_sFirstSlot = NO_ALLOC;
- YSI_g_sLastSlot = NO_ALLOC;
- return timer;
- }
- // Free all timer resources.
- stock _Timer_F(slot)
- {
- P:3("_Timer_F called");
- // This is done here for convenience.
- if (slot & 0x80000000)
- {
- new
- next;
- slot = ~slot; //^= -1;
- for ( ; ; )
- {
- next = mget(Alloc:slot, 0);
- P:6("_Timer_F: slot = %d, next = %d", slot, next);
- // Out of stored strings and arrays.
- if (next == -1)
- {
- KillTimer(mget(Alloc:slot, 1));
- free(Alloc:slot);
- break;
- }
- free(Alloc:slot);
- slot = next;
- }
- }
- else
- {
- KillTimer(slot);
- }
- return 1;
- }
- // Free one timer resource.
- /*stock _Timer_H(slot)
- {
- P:3("_Timer_H called");
- // This is done here for convenience.
- free(Alloc:(slot - 1));
- }*/
- // Free one timer resource. Now actually frees many, not just one.
- /*stock _Timer_H(...)
- {
- P:3("_Timer_H called");
- new
- c = numargs();
- while (c--)
- {
- // This is done here for convenience.
- free(Alloc:(getarg(c) - 1));
- }
- }*/
- stock _Timer_H(slot)
- {
- _Timer_F(~(slot - 1));
- }
- // These are the tag-type definitions for the various possible parameter types.
- // Array-like definitions.
- #define @Yf:@Yg:@Yh:#%0#%1|||%3[%4]|||%5,%6;%8>%9||| @Ye:@Yw:#%0#%1|||%3[%4]|||%5,%6;%9|||
- #define @Ye:@Yw:#%0#%1|||%2string:%3[%4]|||%5,%6;%9||| @Yf:@Yg:@Yh:#%0d#%1,_Timer_S(%3)|||%5|||%6;1>%9,@Yv&%3&|||
- // This one has an extra parameter because arrays must always be followed by
- // their length.
- #define @Yw:#%0#%1|||%3[%4]|||%5,%6,%7;%9||| @Yf:@Yg:@Yh:#%0d#%1,_Timer_A(%3,%5)|||%5|||%6,%7;1>%9,@Yv&%3&|||
- // Tag-like definitions.
- #define @Yg:@Yh:#%0#%1|||%2:%3|||%5,%6;%8>%9||| @Yf:@Yg:@Yh:#%0d#%1,%2:%3|||%5|||%6;%8>%9,%2:%3|||
- // Others.
- #define @Yh:#%0#%1|||%3|||%5,%6;%8>%9||| @Yf:@Yg:@Yh:#%0d#%1,%3|||%5|||%6;%8>%9,%3|||
- // Main entry point for defer type determination.
- #define _YT@CR:%0,%1)%8>%2||| @Yf:@Yg:@Yh:#i#,@Yx:J@|||%0|||%1;%8>%2|||
- // Define for "defer" with timer, parameters and main function.
- #define timer%0[%1]%3(%2) stock%0_yT@(%2)return _Timer_C(O@(#%0@_yT,I@==-1?(%1):I@,J@,_YT@CR:%2,,)0>%0|||%0|||(%2)
- // Expand additional parameters out to three functions after processing.
- //#define @Yx:%0||||||;%1,%2|||%4||| %0),1);@Yu:%1@_yT(%2);public @Yu:%1@_yT(%2){%4(%2);}%4
- #define @Yx:%0||||||;%8>%1,%2|||%4||| %0),%8);@Yj:%1@_yT(__r,%2);public @Yj:%1@_yT(__r,%2){%4(%2);}%4
- // Can't believe I never thought of this before! If only there was a way to
- // make it less generic than "id".
- #define id#,@Yx:J@,||||||;%8>%1,%2|||%4||| ),0);%1@_yT();public%1@_yT(){%4();}%4
- // Remove excess "_Timer_G" and "_Timer_B".
- #define @Yj:%0{%1(%8&%2&%3)%9} @Yj:%0{%1(%8:YSI_gMallocMemory[%2]%3);@Yl(@Yk:%2)%9}
- //#define @Yu:%0{%1(%8&%2&%3)%9} @Yu:%0{%1(%8:YSI_gMallocMemory[%2]%3)%9}
- #define @Yv&%0& %0
- //#define @Yk:%0);@Yl(@Yk:%1); %0,@Yk:%1);
- // I'm not entirely sure why this works in reverse order, but I'm glad it does!
- #define @Yk:%0);@Yl(@Yk:%1); @Yk:%0);
- #define @Yl if(!__r)_Timer_H
- #define string:
- #define defer%0(%1) (J@=0,Timer:%0_yT@(%1))
- #define repeat%0(%1) (J@=1,Timer:%0_yT@(%1))
- #define Timer:%0[%1]_yT@(%2) I@=%1,Timer:%0_yT@(%2)
- #define stop%0; {_Timer_F(_:%0);}
- #endif
- /*============================================================================*\
- *==============================================================================*
- ================================================================================
- |||| ||||
- |||| HERE BEGINS THE OLD VERSION 2! ||||
- |||| ||||
- ================================================================================
- *==============================================================================*
- \*============================================================================*/
- #endinput
- //#define _Timer_G(%0) YSI_gMallocMemory[%0]
- //#define _Timer_B _Timer_G
- /*#define pause_task%0; {%0@yT_(0,-1);}
- #define resume_task%0; {%0@yT_(1,-1);}
- #define pause_ptask%0; {%0@yT_(0,%1);}
- #define resume_ptask%0; {J@=_:@Ym:%0@yT_(1,%1);}*/
- // These are the tag-type definitions for the various possible parameter types.
- //#define @Ya:@Yb:@Yc:@Yd:@Yz:#%0#%1|||%2string:%3[%4]|||%5,%6;%9||| @Ya:@Yb:@Yc:@Yd:@Yz:#%0d#%1,_Timer_S(%3)|||%5|||%6;%9,@Yv<<<%3>>>|||
- // This one has an extra parameter because arrays must always be followed by
- // their length.
- #define @Yb:@Yc:@Yd:@Yz:#%0#%1|||%3[%4]|||%5,%6;%9||| @Ya:@Yy:#%0#%1|||%3[%4]|||%5,%6;%9|||
- //@Ya:@Yb:@Yc:@Yd:@Yz:#%0d#%1,_Timer_A(%3,%5)|||%5|||%6,%7;%9,@Yv<<<%3>>>|||
- #define @Ya:@Yy:#%0#%1|||%2string:%3[%4]|||%5,%6;%9||| @Yb:@Yc:@Yd:@Yz:#%0d#%1,_Timer_S(%3)|||%5|||%6;%9,@Yv&%3&|||
- #define @Yy:#%0#%1|||%3[%4]|||%5,%6,%7;%9||| @Yb:@Yc:@Yd:@Yz:#%0d#%1,_Timer_A(%3,%5)|||%5|||%6,%7;%9,@Yv&%3&|||
- #define @Yc:@Yd:@Yz:#%0#%1|||%2:%3|||%5,%6;%9||| @Yb:@Yc:@Yd:@Yz:#%0d#%1,_:%3|||%5|||%6;%9,%2:%3|||
- #define @Yd:@Yz:#%0#%1|||%3|||%5,%6;%9||| @Yb:@Yc:@Yd:@Yz:#%0d#%1,%3|||%5|||%6;%9,%3|||
- // Main entry point for defer type determination.
- #define _YT@CT:%0,%1)%3;%2||| @Yb:@Yc:@Yd:@Yz:##|||%0|||%1;%2|||
- // Detect zero parameters.
- #define O@(#%0,%1,%2,%6:,,)%7;%3|||%5||| K@(#%0,%1,%2),%7);%3@_yT();public%3@_yT(){%5();}%5
- //#define @Ye:__@Yf=%4)%5O@(#%0#__@Yf,%2,_YT@CT:,,;%3||| __@Yg=%4)return K@(#%0#,__@Yg,%2);%3@_yT();public%3@_yT(){%3_yT@();}
- // Define for "defer" with timer, parameters and main function.
- #define defer%0[%1](%2) stock%0(%2)return _Timer_C(O@(#%0@_yT,I@==-1?(%1):I@,0,_YT@CT:%2,,)0;%0|||%0_yT@|||(%2)
- // This is called if we need to add a leading comma to the time parameter.
- //#define __@Yf ,__@Yg
- // Expand additional parameters out to three functions after processing.
- //#define @Yz:%0||||||;%1,%2|||%3|||%4||| @Yy:@Yw:%0),0);%1@_yT(%2);public%1@_yT(%2){%4(%2);}%3%4
- #define @Yz:%0||||||;%1,%2|||%4||| %0),0);@Yj:%1@_yT(%2);public @Yj:%1@_yT(%2){%4(%2);}%4
- // Remove excess "_Timer_G" and "_Timer_B".
- //#define @Yy:@Yw:%0;%1(%2_Timer_G(%3)%4);%5(%6_Timer_G(%7)%8){%9} @Yy:@Yw:%0;%1(%2%3%4);%5(%6%7%8){%9_Timer_H(%3);}
- //#define @Yw:%0;%1(%2_Timer_B(%3)%4);%5(%6_Timer_B(%7)%8){%9} @Yy:@Yw:%0;%1(%2%3%4);%5(%6%7%8){%9_Timer_H(%3);}
- // Define for "force" to call function quickly.
- //#define force%0[%1](%2) (J@=_:@Yr:@Yq:%0:%1(%2))
- #define force%0(%2) (%0_yT@(%2))
- #define @Yr:@Yq:%0:%2-1(%2) %0_yT@(%2)
- #define @Yq:%0:%1(%2) (I@=(%1),%0(%2))
- #define @%0:%1(%2) (@Yr:@Yq:%1:%0(%2))
- #define after%0(%2) (I@=0,%0(%2))
- // This is the start of the "repeat" code - code for looping timers.
- // These are the tag-type definitions for the various possible parameter types.
- #define @Yf:@Yg:@Yh:@Yx:#%0#%1|||%3[%4]|||%5,%6;%9||| @Ye:@Yw:#%0#%1|||%3[%4]|||%5,%6;%9|||
- #define @Ye:@Yw:#%0#%1|||%2string:%3[%4]|||%5,%6;%9||| @Yf:@Yg:@Yh:@Yx:#%0d#%1,_Timer_S(%3)|||%5|||%6;%9,@Yv&%3&|||
- #define @Yw:#%0#%1|||%3[%4]|||%5,%6,%7;%9||| @Yf:@Yg:@Yh:@Yx:#%0d#%1,_Timer_A(%3,%5)|||%5|||%6,%7;%9,@Yv&%3&|||
- // This one has an extra parameter because arrays must always be followed by
- // their length.
- //#define @Yf:@Yg:@Yh:@Yx:#%0#%1|||%3[%4]|||%5,%6,%7;%9||| @Yf:@Yg:@Yh:@Yx:#%0d#%1,_Timer_A(%3,%5)|||%5|||%6,%7;%9,@Yv<<<%3>>>|||
- #define @Yg:@Yh:@Yx:#%0#%1|||%2:%3|||%5,%6;%9||| @Yf:@Yg:@Yh:@Yx:#%0d#%1,%2:%3|||%5|||%6;%9,%2:%3|||
- #define @Yh:@Yx:#%0#%1|||%3|||%5,%6;%9||| @Yf:@Yg:@Yh:@Yx:#%0d#%1,%3|||%5|||%6;%9,%3|||
- // Main entry point for defer type determination.
- #define _YT@CR:%0,%1)%3;%2||| @Yf:@Yg:@Yh:@Yx:##|||%0|||%1;%2|||
- //#define O@(#%0,%1,%2,%6:,,)%7;%3|||%4|||%5||| K@(#%0,%1,%2),%7);%3@_yT();public%3@_yT(){%5();}%4%5
- // Define for "defer" with timer, parameters and main function.
- //#define defer%0[%1](%2) stock%0(%2)return _Timer_C(O@(#%0@_yT,I@==-1?(%1):I@,0,_YT@CT:%2,,)0;%0||||||%0_yT@|||(%2)
- #define repeat%0[%1](%2) stock%0_yT@(%2)return _Timer_C(O@(#%0@_yT,I@==-1?(%1):I@,1,_YT@CR:%2,,)1;%0|||%0|||(%2)
- //#define @Yi(%0) return _Timer_F(%0);
- // This is called if we need to add a leading comma to the time parameter.
- //#define __@Yf ,__@Yg
- // Expand additional parameters out to three functions after processing.
- //#define @Yx:%0||||||;%1,%2|||%3|||%4||| @Yu:@Yv:%0),1);%1@_yT(%2);public%1@_yT(%2){%4(%2);}%3%4
- #define @Yx:%0||||||;%1,%2|||%4||| %0),1);@Yu:%1@_yT(%2);public @Yu:%1@_yT(%2){%4(%2);}%4
- // Remove excess "_Timer_G" and "_Timer_B".
- //#define @Yu:@Yv:%0;%1(%2_Timer_G(%3)%4);%5(%6_Timer_G(%7)%8) @Yu:@Yv:%0;%1(%2%3%4);%5(%6%7%8)
- //#define @Yv:%0;%1(%2_Timer_B(%3)%4);%5(%6_Timer_B(%7)%8) @Yu:@Yv:%0;%1(%2%3%4);%5(%6%7%8)
- #define @Yj:%0{%1(%8&%2&%3)%9} @Yj:%0{%1(%8:YSI_gMallocMemory[%2]%3);@Yl(@Yk:%2)%9}
- #define @Yu:%0{%1(%8&%2&%3)%9} @Yu:%0{%1(%8:YSI_gMallocMemory[%2]%3)%9}
- #define @Yv&%0& %0
- #define @Yk:%0);@Yl(@Yk:%1); %0,@Yk:%1);
- #define @Yl _Timer_H
- //#define start%0(%1) (J@=%0_yT@(%1))
- #define start%0(%1) (Timer:%0_yT@(%1))
- #define stop%1; {_Timer_F(%1);}
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement