1
0

y_timers.inc 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. /*----------------------------------------------------------------------------*-
  2. ====================================
  3. y_timers - Run timers efficiently.
  4. ====================================
  5. Description:
  6. Sets up repeating timers without requiring any SetTimers and arranges them
  7. so that they will be very unlikely to meet (at least for a long time) using
  8. scheduling algorithms to get timers with the same period to be offset.
  9. Legal:
  10. Version: MPL 1.1
  11. The contents of this file are subject to the Mozilla Public License Version
  12. 1.1 (the "License"); you may not use this file except in compliance with
  13. the License. You may obtain a copy of the License at
  14. http://www.mozilla.org/MPL/
  15. Software distributed under the License is distributed on an "AS IS" basis,
  16. WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  17. for the specific language governing rights and limitations under the
  18. License.
  19. The Original Code is the SA:MP script information include.
  20. The Initial Developer of the Original Code is Alex "Y_Less" Cole.
  21. Portions created by the Initial Developer are Copyright (C) 2008
  22. the Initial Developer. All Rights Reserved.
  23. Contributors:
  24. ZeeX, koolk
  25. Thanks:
  26. Peter, Cam - Support.
  27. ZeeX - Very productive conversations.
  28. koolk - IsPlayerinAreaEx code.
  29. TheAlpha - Danish translation.
  30. breadfish - German translation.
  31. Fireburn - Dutch translation.
  32. yom - French translation.
  33. 50p - Polish translation.
  34. Zamaroht - Spanish translation.
  35. Dracoblue, sintax, mabako, Xtreme, other coders - Producing other modes
  36. for me to strive to better.
  37. Pixels^ - Running XScripters where the idea was born.
  38. Matite - Pestering me to release it and using it.
  39. Very special thanks to:
  40. Thiadmer - PAWN.
  41. Kye/Kalcor - SA:MP.
  42. SA:MP Team past, present and future - SA:MP.
  43. Version:
  44. 1.0
  45. Changelog:
  46. 26/10/10:
  47. Officially added simple calling.
  48. Added "delay" functions.
  49. 12/10/10:
  50. Rewrote for YSI 1.0 using y_scripting.
  51. 11/08/07:
  52. Removed millions of defines to reduce pre-processing.
  53. Added pickups.
  54. 03/08/07:
  55. First version.
  56. -*----------------------------------------------------------------------------*/
  57. #include <YSI\internal\y_version>
  58. #include <YSI\internal\y_shortfunc>
  59. #include <YSI\y_scripting>
  60. #include <YSI\y_debug>
  61. //#define Timer:%0[%1](%2) forward @yT_%1_%0();@yT_%1_%0()
  62. #define Timer:%0[%1](%2) forward @yT_%1_%0();stock %0() @yT_%1_%0();@yT_%1_%0()
  63. #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)
  64. #define FixDelay:%0[%1,%2](%3) stock %0(%3)return O@("@_"#%0,%1,0,#%2#x,%3);forward @_%0(%3);@_%0(%3)
  65. // There's a bug in passing strings to timer functions, so I've remove it.
  66. //#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)
  67. #define skip:%0(%3) @%0(%3)
  68. #define delay:%0[%1](%3) v@%0(_:%1,%3)
  69. // This defines the number of different periods that timers can have. This
  70. // number is a HUGE over-estimate, you would need to have over 256 timers, none
  71. // of them with the same period, for this number to be too small!
  72. #define MAX_TIMER_VARIATIONS (256)
  73. forward Timer_Start(timer, delay);
  74. /*----------------------------------------------------------------------------*-
  75. Function:
  76. OnScriptInit
  77. Params:
  78. -
  79. Return:
  80. -
  81. Notes:
  82. -
  83. -*----------------------------------------------------------------------------*/
  84. #if defined FILTERSCRIPT
  85. public OnFilterScriptInit()
  86. #else
  87. public OnGameModeInit()
  88. #endif
  89. {
  90. new
  91. buffer[32],
  92. idx = 0,
  93. timers[MAX_TIMER_VARIATIONS][2],//[3],
  94. periods = 0;
  95. // 0 = time, 1 = count, 2 = offset.
  96. // First loop - get all the different periods.
  97. // Get the list of timers from the list of publics.
  98. while ((idx = Scripting_GetPublicFast(idx, buffer, (Scripting_FastString('@', 'y', 'T', '_')))))
  99. {
  100. // Get the time associated with the timer. We know this starts at index
  101. // position 4, because we always set it to be there.
  102. new
  103. time = strval(buffer[4]);
  104. if (time)
  105. {
  106. // Valid time, find this in the array.
  107. for (new i = 0; ; ++i)
  108. {
  109. if (i == periods)
  110. {
  111. timers[i][0] = time;
  112. timers[i][1] = 1;
  113. ++periods;
  114. break;
  115. }
  116. else if (timers[i][0] == time)
  117. {
  118. ++timers[i][1];
  119. break;
  120. }
  121. }
  122. if (periods == MAX_TIMER_VARIATIONS)
  123. {
  124. P:1("*** Internal Error: Timer array full");
  125. break;
  126. }
  127. }
  128. }
  129. // Group timers with common periods together, for example timers with 1000
  130. // and 500ms periods need to be interleaved so they don't run at the same
  131. // time very often. Obviously ANY combination of timers will eventually run
  132. // at the same time at some point, but we can reduce this chance.
  133. /*for (new i = 0; i != periods; ++i)
  134. {
  135. new
  136. time = timers[i][0];
  137. if (timers[i][2])
  138. {
  139. for (new j = 0; j != i; ++j)
  140. {
  141. new
  142. ct = timers[j][0];
  143. if ((time / ct) * ct == time || (ct / time) * time == ct)
  144. {
  145. // Set the count to the same as the master.
  146. timers[i][1] = timers[j][1];
  147. break;
  148. }
  149. }
  150. }
  151. else
  152. {
  153. new
  154. offset = timers[i][1];
  155. for (new j = i + 1; j != periods; ++j)
  156. {
  157. // Find similar periods.
  158. new
  159. ct = timers[j][0];
  160. if ((time / ct) * ct == time)
  161. {
  162. // This time is larger.
  163. }
  164. else if ((ct / time) * time == ct)
  165. {
  166. }
  167. if ((time / ct) * ct == time || (ct / time) * time == ct)
  168. {
  169. // That's integer division, so valid code. Mark this
  170. // element as controlled by another element.
  171. timers[j][2] = offset;
  172. offset += timers[j][1];
  173. }
  174. }
  175. timers[i][1] = offset;
  176. }
  177. }*/
  178. C:1(for(new i;i!=periods;++i)printf("%d %d %d",timers[i][0],timers[i][1],0););//,timers[i][2]););
  179. // Now we know how many of each period there are we can try arrange them so
  180. // that they execute at very different times.
  181. // [1] contains the total number of timers on similar periods.
  182. for (new i = 0; i != periods; ++i)
  183. {
  184. // First calculate the gap between the timers.
  185. new
  186. time = timers[i][0],
  187. offset = time / timers[i][1];
  188. // Now start all the timers with this time at that offset.
  189. idx = 0;
  190. new
  191. last = 0,
  192. curo = offset;
  193. while ((idx = Scripting_GetPublicFast(idx, buffer, (Scripting_FastString('@', 'y', 'T', '_')))))
  194. {
  195. if (strval(buffer[4]) == time)
  196. {
  197. // That's the old start code, which uses 7ms offsets to try get
  198. // as close as possible to different server frames (5ms).
  199. SetTimerEx("Timer_Start", curo + (random(14) - 7), 0, "ii", last, time);
  200. //SetTimerEx("Timer_Start", curo, 0, "ii", last, time);
  201. curo += offset;
  202. }
  203. // So that the first found timer in the next function is correct.
  204. last = idx;
  205. }
  206. }
  207. CallLocalFunction("Timers_OnScriptInit", "");
  208. }
  209. #if defined FILTERSCRIPT
  210. #if defined _ALS_OnFilterScriptInit
  211. #undef OnFilterScriptInit
  212. #else
  213. #define _ALS_OnFilterScriptInit
  214. #endif
  215. #define OnFilterScriptInit Timers_OnScriptInit
  216. #else
  217. #if defined _ALS_OnGameModeInit
  218. #undef OnGameModeInit
  219. #else
  220. #define _ALS_OnGameModeInit
  221. #endif
  222. #define OnGameModeInit Timers_OnScriptInit
  223. #endif
  224. forward Timers_OnScriptInit();
  225. /*----------------------------------------------------------------------------*-
  226. Function:
  227. Timer_Start
  228. Params:
  229. timer - Approximate public function index.
  230. delay - How often it's called.
  231. Return:
  232. -
  233. Notes:
  234. Only needed for more than one timer. Offsets calls from each other for
  235. better server load distribution.
  236. -*----------------------------------------------------------------------------*/
  237. public Timer_Start(timer, delay)
  238. {
  239. new
  240. buffer[32];
  241. Scripting_GetPublicFast(timer, buffer, (Scripting_FastString('@', 'y', 'T', '_')));
  242. SetTimer(buffer, delay, 1);
  243. }