| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264 |
- /*----------------------------------------------------------------------------*-
- ====================================
- 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.
- 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 SA:MP script information include.
-
- The Initial Developer of the Original Code is Alex "Y_Less" Cole.
- Portions created by the Initial Developer are Copyright (C) 2008
- the Initial Developer. All Rights Reserved.
-
- Contributors:
- ZeeX, koolk
-
- Thanks:
- Peter, Cam - Support.
- 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.
- Kye/Kalcor - SA:MP.
- SA:MP Team past, present and future - SA:MP.
- Version:
- 1.0
- Changelog:
- 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.
- -*----------------------------------------------------------------------------*/
- #include <YSI\internal\y_shortfunc>
- #include <YSI\y_scripting>
- #include <YSI\y_debug>
- //#define Timer:%0[%1](%2) forward @yT_%1_%0();@yT_%1_%0()
- #define Timer:%0[%1](%2) forward @yT_%1_%0();stock %0() @yT_%1_%0();@yT_%1_%0()
- #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);forward @%0(%3);@%0(%3)
- #define FixDelay:%0[%1,%2](%3) stock %0(%3)return O@("@_"#%0,%1,0,#%2#x,%3);forward @_%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)
- forward Timer_Start(timer, delay);
- /*----------------------------------------------------------------------------*-
- Function:
- OnScriptInit
- Params:
- -
- Return:
- -
- Notes:
- -
- -*----------------------------------------------------------------------------*/
- #if defined FILTERSCRIPT
- public OnFilterScriptInit()
- #else
- public OnGameModeInit()
- #endif
- {
- 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 = Scripting_GetPublicFast(idx, buffer, (Scripting_FastString('@', 'y', 'T', '_')))))
- {
- // 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[4]);
- 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:1("*** Internal Error: 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;
- }
- }*/
- 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 = Scripting_GetPublicFast(idx, buffer, (Scripting_FastString('@', 'y', 'T', '_')))))
- {
- if (strval(buffer[4]) == 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;
- }
- }
- CallLocalFunction("Timers_OnScriptInit", "");
- }
- #if defined FILTERSCRIPT
- #if defined _ALS_OnFilterScriptInit
- #undef OnFilterScriptInit
- #else
- #define _ALS_OnFilterScriptInit
- #endif
- #define OnFilterScriptInit Timers_OnScriptInit
- #else
- #if defined _ALS_OnGameModeInit
- #undef OnGameModeInit
- #else
- #define _ALS_OnGameModeInit
- #endif
- #define OnGameModeInit Timers_OnScriptInit
- #endif
- forward Timers_OnScriptInit();
- /*----------------------------------------------------------------------------*-
- 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];
- Scripting_GetPublicFast(timer, buffer, (Scripting_FastString('@', 'y', 'T', '_')));
- SetTimer(buffer, delay, 1);
- }
|