Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*============================================================================*\
- *==============================================================================*
- ================================================================================
- |||| ||||
- |||| 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)
- 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 + 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);
- // This is done here for convenience.
- I@ = -1;
- // Only repeating timers are freed like this.
- 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 0;
- }
- // Free all timer resources.
- stock _Timer_F(slot)
- {
- P:3("_Timer_F called");
- // This is done here for convenience.
- 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;
- }
- 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));
- }
- }
- //#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@=_:hym:%0@yT_(1,%1);}*/
- #define pause%0; {J@=_:hym:%0@yT_(0,-1);}
- #define resume%0; {J@=_:hym:%0@yT_(1,-1);}
- #define hym:%0:%1@yT_(%2,-1) %0@yT_(%2,%1)
- // These are the tag-type definitions for the various possible parameter types.
- //#define hya:hyb:hyc:hyd:hyz:#%0#%1|||%2string:%3[%4]|||%5,%6;%9||| hya:hyb:hyc:hyd:hyz:#%0d#%1,_Timer_S(%3)|||%5|||%6;%9,hyv<<<%3>>>|||
- // This one has an extra parameter because arrays must always be followed by
- // their length.
- #define hyb:hyc:hyd:hyz:#%0#%1|||%3[%4]|||%5,%6;%9||| hya:hyy:#%0#%1|||%3[%4]|||%5,%6;%9|||
- //hya:hyb:hyc:hyd:hyz:#%0d#%1,_Timer_A(%3,%5)|||%5|||%6,%7;%9,hyv<<<%3>>>|||
- #define hya:hyy:#%0#%1|||%2string:%3[%4]|||%5,%6;%9||| hyb:hyc:hyd:hyz:#%0d#%1,_Timer_S(%3)|||%5|||%6;%9,hyv&%3&|||
- #define hyy:#%0#%1|||%3[%4]|||%5,%6,%7;%9||| hyb:hyc:hyd:hyz:#%0d#%1,_Timer_A(%3,%5)|||%5|||%6,%7;%9,hyv&%3&|||
- #define hyc:hyd:hyz:#%0#%1|||%2:%3|||%5,%6;%9||| hyb:hyc:hyd:hyz:#%0d#%1,_:%3|||%5|||%6;%9,%2:%3|||
- #define hyd:hyz:#%0#%1|||%3|||%5,%6;%9||| hyb:hyc:hyd:hyz:#%0d#%1,%3|||%5|||%6;%9,%3|||
- // Main entry point for defer type determination.
- #define _YT@CT:%0,%1)%3;%2||| hyb:hyc:hyd:hyz:##|||%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 hye:__hyf=%4)%5O@(#%0#__hyf,%2,_YT@CT:,,;%3||| __hyg=%4)return K@(#%0#,__hyg,%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 __hyf ,__hyg
- // Expand additional parameters out to three functions after processing.
- //#define hyz:%0||||||;%1,%2|||%3|||%4||| hyy:hyw:%0),0);%1@_yT(%2);public%1@_yT(%2){%4(%2);}%3%4
- #define hyz:%0||||||;%1,%2|||%4||| %0),0);hyj:%1@_yT(%2);public hyj:%1@_yT(%2){%4(%2);}%4
- // Remove excess "_Timer_G" and "_Timer_B".
- //#define hyy:hyw:%0;%1(%2_Timer_G(%3)%4);%5(%6_Timer_G(%7)%8){%9} hyy:hyw:%0;%1(%2%3%4);%5(%6%7%8){%9_Timer_H(%3);}
- //#define hyw:%0;%1(%2_Timer_B(%3)%4);%5(%6_Timer_B(%7)%8){%9} hyy:hyw:%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@=_:hyr:hyq:%0:%1(%2))
- #define force%0(%2) (%0_yT@(%2))
- #define hyr:hyq:%0:%2-1(%2) %0_yT@(%2)
- #define hyq:%0:%1(%2) (I@=(%1),%0(%2))
- #define @%0:%1(%2) (hyr:hyq:%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 hyf:hyg:hyh:hyx:#%0#%1|||%3[%4]|||%5,%6;%9||| hye:hyw:#%0#%1|||%3[%4]|||%5,%6;%9|||
- #define hye:hyw:#%0#%1|||%2string:%3[%4]|||%5,%6;%9||| hyf:hyg:hyh:hyx:#%0d#%1,_Timer_S(%3)|||%5|||%6;%9,hyv&%3&|||
- #define hyw:#%0#%1|||%3[%4]|||%5,%6,%7;%9||| hyf:hyg:hyh:hyx:#%0d#%1,_Timer_A(%3,%5)|||%5|||%6,%7;%9,hyv&%3&|||
- // This one has an extra parameter because arrays must always be followed by
- // their length.
- //#define hyf:hyg:hyh:hyx:#%0#%1|||%3[%4]|||%5,%6,%7;%9||| hyf:hyg:hyh:hyx:#%0d#%1,_Timer_A(%3,%5)|||%5|||%6,%7;%9,hyv<<<%3>>>|||
- #define hyg:hyh:hyx:#%0#%1|||%2:%3|||%5,%6;%9||| hyf:hyg:hyh:hyx:#%0d#%1,%2:%3|||%5|||%6;%9,%2:%3|||
- #define hyh:hyx:#%0#%1|||%3|||%5,%6;%9||| hyf:hyg:hyh:hyx:#%0d#%1,%3|||%5|||%6;%9,%3|||
- // Main entry point for defer type determination.
- #define _YT@CR:%0,%1)%3;%2||| hyf:hyg:hyh:hyx:##|||%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 hyi(%0) return _Timer_F(%0);
- // This is called if we need to add a leading comma to the time parameter.
- //#define __hyf ,__hyg
- // Expand additional parameters out to three functions after processing.
- //#define hyx:%0||||||;%1,%2|||%3|||%4||| hyu:hyv:%0),1);%1@_yT(%2);public%1@_yT(%2){%4(%2);}%3%4
- #define hyx:%0||||||;%1,%2|||%4||| %0),1);hyu:%1@_yT(%2);public hyu:%1@_yT(%2){%4(%2);}%4
- // Remove excess "_Timer_G" and "_Timer_B".
- //#define hyu:hyv:%0;%1(%2_Timer_G(%3)%4);%5(%6_Timer_G(%7)%8) hyu:hyv:%0;%1(%2%3%4);%5(%6%7%8)
- //#define hyv:%0;%1(%2_Timer_B(%3)%4);%5(%6_Timer_B(%7)%8) hyu:hyv:%0;%1(%2%3%4);%5(%6%7%8)
- #define hyj:%0{%1(%8&%2&%3)%9} hyj:%0{%1(%8:YSI_gMallocMemory[%2]%3);hyl(hyk:%2)%9}
- #define hyu:%0{%1(%8&%2&%3)%9} hyu:%0{%1(%8:YSI_gMallocMemory[%2]%3)%9}
- #define hyv&%0& %0
- #define hyk:%0);hyl(hyk:%1); %0,hyk:%1);
- #define hyl _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