Guest User

Untitled

a guest
Feb 28th, 2015
461
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 9.35 KB | None | 0 0
  1. #include "internal\y_version"
  2.  
  3. #include "y_amx"
  4. #include "internal\y_shortfunc"
  5. #include "y_malloc"
  6. #include "y_iterate"
  7. #include "y_hooks"
  8. #include "y_debug"
  9.  
  10. static stock
  11. Alloc:YSI_g_sLastSlot = NO_ALLOC,
  12. Alloc:YSI_g_sFirstSlot = NO_ALLOC,
  13. YSI_g_sPlayerTimers = -1;
  14.  
  15. hook OnScriptInit()
  16. {
  17. P:1("hook Timers_OnScriptInit called");
  18. new
  19. pointer,
  20. time,
  21. idx,
  22. entry;
  23. while ((idx = AMX_GetPublicEntrySuffix(idx, entry, _A<@yT_>)))
  24. //while ((idx = AMX_GetPublicPointerSuffix(idx, pointer, _A<@yT_>)))
  25. {
  26. P:6("Timer_OnScriptInit: entry: %d", entry);
  27. #emit LREF.S.pri entry
  28. #emit STOR.S.pri pointer
  29. //YSI_g_sCurFunc = pointer;
  30. // Don't bother with the real name, call the function by address to get
  31. // the time the function runs for.
  32. P:7("Timer_OnScriptInit: pointer: %d", pointer);
  33. // Push the address of the current function.
  34. #emit PUSH.S pointer
  35. #emit PUSH.C 0xFFFFFFFF
  36. #emit PUSH.C 8
  37. #emit LCTRL 6
  38. #emit ADD.C 28
  39. #emit PUSH.pri
  40. #emit LOAD.S.pri pointer
  41. #emit SCTRL 6
  42. #emit STOR.S.pri time
  43. //YSI_g_sCurFunc = 0;
  44. P:7("Timer_OnScriptInit: time: %d", time);
  45. if (time != -1)
  46. {
  47. // Find all the functions with the same time. This is less
  48. // efficient than previous implementations (it is O(N^2)), but also
  49. // more robust as it won't fail no matter how many different times
  50. // there are - old ones relied on an array with a finite size.
  51. new
  52. pointer2,
  53. time2,
  54. idx2,
  55. total,
  56. pre;
  57. while ((idx2 = AMX_GetPublicPointerSuffix(idx2, pointer2, _A<@yT_>)))
  58. {
  59. // Call the functions a second time to guarantee getting
  60. #emit PUSH.C 0
  61. #emit PUSH.C 0xFFFFFFFF
  62. #emit PUSH.C 8
  63. #emit LCTRL 6
  64. #emit ADD.C 28
  65. #emit PUSH.pri
  66. #emit LOAD.S.pri pointer2
  67. #emit SCTRL 6
  68. #emit STOR.S.pri time2
  69. // Check if the new time is a FACTOR, SAME, or MULTIPLE of this
  70. // task, so we don't start different timers together.
  71. if (time2 == time || time / time2 * time2 == time || time2 / time * time == time2)
  72. {
  73. ++total;
  74. if (idx2 < idx)
  75. {
  76. ++pre;
  77. }
  78. }
  79. }
  80. P:7("Timer_OnScriptInit: total: %d, time: %d, pre: %d", total, time, pre);
  81. // Now we know what time this function has, how many others have
  82. // that time and how many have already been started.
  83. new
  84. buffer[32];
  85. entry += 4;
  86. #emit LREF.S.pri entry
  87. #emit STOR.S.pri pointer
  88. AMX_ReadString(AMX_BASE_ADDRESS + pointer, buffer);
  89. P:7("Timer_OnScriptInit: %s", unpack(buffer));
  90. // Get the time offset for the current call. This should mean that
  91. // all the functions are nicely spread out.
  92. SetTimerEx(buffer, time * pre / total, 0, "ii", 1, -1);
  93. }
  94. }
  95. P:1("hook Timers_OnScriptInit ended");
  96. }
  97.  
  98. hook OnPlayerConnect(playerid)
  99. {
  100. P:1("hook Timers_OnPlayerConnect called: %d", playerid);
  101. // Loop through all the per-player timers. Correctly finds them all from a
  102. // linked list hidden in static variables (which are really global).
  103. new
  104. cur = YSI_g_sPlayerTimers,
  105. data;
  106. while (cur != -1)
  107. {
  108. #emit LREF.S.pri cur
  109. #emit STOR.S.pri data
  110. P:6("Timers_OnPlayerConnect: func: %x", data);
  111. // Start this timer for this player.
  112. #emit PUSH.S playerid
  113. #emit PUSH.C 1
  114. // Push the parameter count (in bytes). This is actually passed to
  115. // native functions directly.
  116. #emit PUSH.C 8
  117. // Call the function currently in the list to trigger the repeating
  118. // timer. This involves getting the current "cip" address, modifying it
  119. // to get the return address then modifying "cip" to call the function.
  120. #emit LCTRL 6
  121. #emit ADD.C 28
  122. #emit PUSH.pri
  123. #emit LOAD.S.pri data
  124. #emit SCTRL 6
  125. // Returned, get the next list element.
  126. cur += 4;
  127. #emit LREF.S.pri cur
  128. #emit STOR.S.pri cur
  129. }
  130. P:1("hook Timers_OnPlayerConnect ended");
  131. }
  132.  
  133. hook OnPlayerDisconnect(playerid, reason)
  134. {
  135. P:1("hook Timers_OnPlayerDisconnect called: %d, %d, playerid, reason");
  136. // Loop through all the per-player timers. Correctly finds them all from a
  137. // linked list hidden in static variables (which are really global).
  138. new
  139. cur = YSI_g_sPlayerTimers,
  140. data;
  141. while (cur != -1)
  142. {
  143. #emit LREF.S.pri cur
  144. #emit STOR.S.pri data
  145. P:6("Timers_OnPlayerDisconnect: func: %x", data);
  146. // End this timer for this player.
  147. #emit PUSH.S playerid
  148. #emit PUSH.C 0
  149. // Push the parameter count (in bytes). This is actually passed to
  150. // native functions directly.
  151. #emit PUSH.C 8
  152. // Call the function currently in the list to trigger the repeating
  153. // timer. This involves getting the current "cip" address, modifying it
  154. // to get the return address then modifying "cip" to call the function.
  155. #emit LCTRL 6
  156. #emit ADD.C 28
  157. #emit PUSH.pri
  158. #emit LOAD.S.pri data
  159. #emit SCTRL 6
  160. // Returned, get the next list element.
  161. cur += 4;
  162. #emit LREF.S.pri cur
  163. #emit STOR.S.pri cur
  164. }
  165. P:1("hook Timers_OnPlayerDisconnect ended");
  166. }
  167.  
  168. stock _Timer_I(func[], interval, action, &result)
  169. {
  170. P:3("_Timer_I called");
  171. switch (action)
  172. {
  173. case 0:
  174. {
  175. if (result != -1)
  176. {
  177. KillTimer(result),
  178. result =- 1;
  179. }
  180. }
  181. case 1:
  182. {
  183. if (result == -1)
  184. {
  185. result = SetTimer(func, interval, 1);
  186. }
  187. }
  188. }
  189. return interval;
  190. }
  191.  
  192. // Attempt to stop or start a task, possibly for a single player.
  193. stock _Timer_D(func[], interval, const action, who, results[MAX_PLAYERS], &pp, a[2])
  194. {
  195. P:3("_Timer_D called");
  196. switch (action)
  197. {
  198. case -1:
  199. {
  200. if (who)
  201. {
  202. a[0] = who;
  203. a[1] = YSI_g_sPlayerTimers;
  204. // Store the address of the global array.
  205. #emit LOAD.S.pri a
  206. #emit STOR.pri YSI_g_sPlayerTimers
  207. }
  208. }
  209. case 0:
  210. {
  211. // Stop the timer.
  212. if (who == -1)
  213. {
  214. pp = 0;
  215. }
  216. else if (results[who] != -1)
  217. {
  218. KillTimer(results[who]);
  219. results[who] = -1;
  220. }
  221. }
  222. case 1:
  223. {
  224. // Start the timer.
  225. if (who == -1)
  226. {
  227. pp = 1;
  228. }
  229. else if (results[who] == -1)
  230. {
  231. results[who] = SetTimerEx(func, interval, true, "i", who);
  232. }
  233. }
  234. }
  235. // No global interval for per-player timers.
  236. return -1;
  237. }
  238.  
  239. static stock Alloc:Timer_GetSingleSlot(len)
  240. {
  241. // Allocates memory and secretly appends data to the start.
  242. P:4("Timer_GetSingleSlot called: %d", len);
  243. new
  244. Alloc:slot = malloc(len + 1);
  245. if (slot == NO_ALLOC)
  246. {
  247. return NO_ALLOC;
  248. }
  249. P:5("Timer_GetSingleSlot: %d, %d, %d", _:YSI_g_sFirstSlot, _:YSI_g_sLastSlot, _:slot);
  250. // Standard linked list.
  251. if (YSI_g_sFirstSlot == NO_ALLOC)
  252. {
  253. YSI_g_sFirstSlot = slot;
  254. }
  255. else
  256. {
  257. mset(YSI_g_sLastSlot, 0, _:slot);
  258. }
  259. YSI_g_sLastSlot = slot;
  260. mset(YSI_g_sLastSlot, 0, -1);
  261. return slot;// + Alloc:1;
  262. }
  263.  
  264. // Allocate memory to store a string.
  265. stock _Timer_S(string:str[])
  266. {
  267. P:3("_Timer_S called");
  268. new
  269. len = strlen(str);
  270. if (len & 0x0F)
  271. {
  272. len = (len & ~0x0F) + 32;
  273. }
  274. new
  275. Alloc:slot = Timer_GetSingleSlot(len + 1);
  276. if (slot != NO_ALLOC)
  277. {
  278. msets(slot, 1, str);
  279. }
  280. P:5("str: %d", _:slot);
  281. return _:slot + 1;
  282. }
  283.  
  284. // Allocate memory to store an array.
  285. stock _Timer_A(str[], len)
  286. {
  287. P:3("_Timer_A called");
  288. new
  289. Alloc:slot = Timer_GetSingleSlot(len);
  290. if (slot != NO_ALLOC)
  291. {
  292. mseta(slot, 1, str, len);
  293. }
  294. P:5("str: %d", _:slot);
  295. return _:slot + 1;
  296. }
  297.  
  298. //stock
  299. // I@ = -1;
  300.  
  301. // Create the timer setup.
  302. stock _Timer_C(tt, g)
  303. {
  304. P:3("_Timer_C called: %d, %d", tt, g);
  305. //P:3("_Timer_C called: %d", tt);
  306. // This is done here for convenience.
  307. I@ = -1;
  308. // Only repeating timers are freed like this.
  309. // UPDATE: Now all timers with array parameters, regardless of repeat status
  310. // are freed like this. Only timers with no malloc aren't.
  311. if (g)
  312. {
  313. new
  314. Alloc:slot = Timer_GetSingleSlot(1);
  315. P:5("_Timer_C: slot = %d", _:slot);
  316. if (slot == NO_ALLOC)
  317. {
  318. // Not a graceful fail!
  319. return 0;
  320. }
  321. mset(slot, 1, tt);
  322. // Just so it isn't a real timer ID (or possibly isn't).
  323. slot = ~YSI_g_sFirstSlot;// ^ Alloc:-1;
  324. YSI_g_sFirstSlot = NO_ALLOC;
  325. YSI_g_sLastSlot = NO_ALLOC;
  326. return _:slot;
  327. }
  328. // Reset these variables on all timers, including self-cleaning ones.
  329. YSI_g_sFirstSlot = NO_ALLOC;
  330. YSI_g_sLastSlot = NO_ALLOC;
  331. return tt;
  332. }
  333.  
  334. // Free all timer resources.
  335. stock _Timer_F(slot)
  336. {
  337. P:3("_Timer_F called");
  338. // This is done here for convenience.
  339. if (slot & 0x80000000)
  340. {
  341. new
  342. next;
  343. slot = ~slot; //^= -1;
  344. for ( ; ; )
  345. {
  346. next = mget(Alloc:slot, 0);
  347. P:6("_Timer_F: slot = %d, next = %d", slot, next);
  348. // Out of stored strings and arrays.
  349. if (next == -1)
  350. {
  351. KillTimer(mget(Alloc:slot, 1));
  352. free(Alloc:slot);
  353. break;
  354. }
  355. free(Alloc:slot);
  356. slot = next;
  357. }
  358. }
  359. else
  360. {
  361. KillTimer(slot);
  362. }
  363. return 1;
  364. }
  365.  
  366. stock _Timer_H(slot)
  367. {
  368. _Timer_F(~(slot - 1));
  369. }
  370.  
  371. #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()
  372.  
  373. #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)
  374.  
  375. #define pause%0; {J@=_:@Ym:%0@yT_(0,-1);}
  376. #define resume%0; {J@=_:@Ym:%0@yT_(1,-1);}
  377. #define @Ym:%0[%1]@yT_(%2,-1) %0@yT_(%2,%1)
  378.  
  379. #define timerfunc YSI_timer
  380.  
  381. #if !defined YSI_NO_timer
  382. #define timer YSI_timer
  383. #endif
Advertisement
Add Comment
Please, Sign In to add comment