slice29a

TimerFix 2 beta 2

Feb 13th, 2012
6,106
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Pawn 8.01 KB | None | 0 0
  1. // TimerFix v2 beta by Slice
  2.  
  3. #if !defined _samp_included
  4.     #error Please include a_samp before Timer Fix.
  5. #endif
  6.  
  7. #if !defined TIMER_FIX_TICK_INTERVAL
  8.     #define TIMER_FIX_TICK_INTERVAL  5
  9. #endif
  10.  
  11. #if !defined TIMER_FIX_TIMER_SLOTS
  12.     #define TIMER_FIX_TIMER_SLOTS  128
  13. #endif
  14.  
  15. #if !defined TIMER_FIX_MAX_ARGUMENTS
  16.     #define TIMER_FIX_MAX_ARGUMENTS  32
  17. #endif
  18.  
  19. #if !defined TIMER_FIX_PERFORMANCE_CHECKS
  20.     #define TIMER_FIX_PERFORMANCE_CHECKS  true
  21. #endif
  22.  
  23. #if !defined TIMER_FIX_DEBUG
  24.     #define TIMER_FIX_DEBUG  false
  25. #endif
  26.  
  27. #define TF::  TF_
  28.  
  29. enum TF::e_TIMER {
  30.     bool:e_bIsUsed,
  31.          e_iNumArguments,
  32.          e_axArguments[TIMER_FIX_MAX_ARGUMENTS],
  33. #if TIMER_FIX_DEBUG
  34.          e_aiArgumentTypes[TIMER_FIX_MAX_ARGUMENTS],
  35. #endif
  36.          e_iFunctionAddress,
  37.          e_szFunctionName[32],
  38.          e_iInterval,
  39.          e_iNextCall,
  40.     bool:e_bIsRepeating
  41. };
  42.  
  43. static
  44. #if TIMER_FIX_DEBUG
  45.     TF::gs_szDebugBuffer[512],
  46. #endif
  47.     TF::gs_Timers[TIMER_FIX_TIMER_SLOTS][TF::e_TIMER],
  48.     TF::gs_iCurrentTimer = -1
  49. ;
  50.  
  51. // Fix for y_timers
  52. #define _Timer_C(O@  _Timer_C(SetTimerEx
  53.  
  54. stock SetTimerHook(const szFunctionName[], iInterval, {bool, _}:bRepeating, const szFormat[] = !"", {_, PlayerText3D, Text, Text3D, Menu, DB, DBResult, File, Float}:...) {
  55.     static
  56.         bool:s_bTimerTickTimerStarted = false
  57.     ;
  58.    
  59.     if (!s_bTimerTickTimerStarted) {
  60.         SetTimer(!"TF_TimerTick", TIMER_FIX_TICK_INTERVAL, true);
  61.        
  62.         s_bTimerTickTimerStarted = true;
  63.     }
  64.    
  65.     new
  66.         iSlot = -1
  67.     ;
  68.    
  69.     for (new i = 0; i < sizeof(TF::gs_Timers); i++) {
  70.         if (!TF::gs_Timers[i][e_bIsUsed]) {
  71.             iSlot = i;
  72.            
  73.             break;
  74.         }
  75.     }
  76.    
  77.     if (iSlot == -1) {
  78.         print(!"(TimerFix) ERROR: Ran out of timer slots. Increase TIMER_FIX_TIMER_SLOTS (current value: " #TIMER_FIX_TIMER_SLOTS ").");
  79.        
  80.         return -1;
  81.     }
  82.    
  83.     if (!(TF::gs_Timers[iSlot][e_iFunctionAddress] = TF::GetPublicFunctionAddress(szFunctionName))) {
  84.         new
  85.             szFunctionNameUnpacked[32]
  86.         ;
  87.        
  88.         strunpack(szFunctionNameUnpacked, szFunctionName);
  89.        
  90.         printf("(TimerFix) ERROR: Invalid function (\"%s\").", szFunctionNameUnpacked);
  91.        
  92.         return -1;
  93.     }
  94.    
  95.     new
  96.         #if TIMER_FIX_DEBUG
  97.             bool:bFormatIsPacked = ispacked(szFormat),
  98.         #endif
  99.                  iNumArgs = max(0, numargs() - 4)
  100.     ;
  101.    
  102.     if (iNumArgs != strlen(szFormat)) {
  103.         new
  104.             szFormatUnpacked[128 char]
  105.         ;
  106.        
  107.         strunpack(szFormatUnpacked, szFormat);
  108.        
  109.         printf("(TimerFix) ERROR: The number of arguments (%d) doesn't match the number of arguments in the format specifier (\"%s\").", iNumArgs, szFormatUnpacked);
  110.        
  111.         return -1;
  112.     }
  113.    
  114.     TF::gs_Timers[iSlot][e_bIsUsed]       = true;
  115.     TF::gs_Timers[iSlot][e_bIsRepeating]  = bRepeating;
  116.     TF::gs_Timers[iSlot][e_iInterval]     = iInterval;
  117.     TF::gs_Timers[iSlot][e_iNextCall]     = GetTickCount() + iInterval;
  118.     TF::gs_Timers[iSlot][e_iNumArguments] = iNumArgs;
  119.    
  120.     strunpack(TF::gs_Timers[iSlot][e_szFunctionName], szFunctionName, 32);
  121.    
  122.     for (new i = 0; i < iNumArgs; i++) {
  123.         TF::gs_Timers[iSlot][e_axArguments][i] = getarg(4 + i);
  124.        
  125.         #if TIMER_FIX_DEBUG
  126.             TF::gs_Timers[iSlot][e_aiArgumentTypes][i] = bFormatIsPacked ? szFormat{i} : szFormat[i];
  127.         #endif
  128.     }
  129.    
  130.     #if TIMER_FIX_DEBUG
  131.         printf("(TimerFix) DEBUG: Timer created; %d = \"%s\".", iSlot, TF::gs_Timers[iSlot][e_szFunctionName]);
  132.     #endif
  133.    
  134.     return iSlot;
  135. }
  136.  
  137. stock KillTimerHook(iTimer) {
  138.     if (0 <= iTimer < sizeof(TF::gs_Timers)) {
  139.         if (TF::gs_Timers[iTimer][e_bIsUsed]) {
  140.             TF::gs_Timers[iTimer][e_bIsUsed] = false;
  141.            
  142.             #if TIMER_FIX_DEBUG
  143.                 printf("(TimerFix) DEBUG: Killed timer %d (\"%s\").", iTimer, TF::gs_Timers[iTimer][e_szFunctionName]);
  144.             #endif
  145.            
  146.             return true;
  147.         }
  148.     }
  149.    
  150.     #if TIMER_FIX_DEBUG
  151.         printf("(TimerFix) DEBUG: Failed to kill timer %d; not in use / invalid id.", iTimer);
  152.     #endif
  153.    
  154.     return false;
  155. }
  156.  
  157. #define SetTimer    SetTimerHook
  158. #define SetTimerEx  SetTimerHook
  159. #define KillTimer   KillTimerHook
  160.  
  161. stock KillThisTimer() {
  162.     if (TF::gs_iCurrentTimer != -1)
  163.         KillTimer(TF::gs_iCurrentTimer);
  164. }
  165.  
  166. forward TF::TimerTick();
  167. public TF::TimerTick() {
  168.     new
  169.         iTick,
  170.         iFunc,
  171.         iArg,
  172.         i, j
  173.     ;
  174.    
  175.     if (TF::gs_iCurrentTimer != -1) {
  176.         printf("(TimerFix) ERROR: The function \"%s\" didn't properly execute, some timers might not have been called.", TF::gs_Timers[TF::gs_iCurrentTimer][e_szFunctionName]);
  177.        
  178.         TF::gs_iCurrentTimer = -1;
  179.     }
  180.    
  181.     for (i = 0; i < sizeof(TF::gs_Timers); i++) {
  182.         if (!TF::gs_Timers[i][e_bIsUsed])
  183.             continue;
  184.        
  185.         if ((iTick = GetTickCount()) >= TF::gs_Timers[i][e_iNextCall]) {
  186.             iFunc = TF::gs_Timers[i][e_iFunctionAddress];
  187.            
  188.             // This is done before and after execution, in case execution fails
  189.             if (TF::gs_Timers[i][e_bIsRepeating])
  190.                 TF::gs_Timers[i][e_iNextCall] = iTick + TF::gs_Timers[i][e_iInterval] - 1;
  191.            
  192.             #if TIMER_FIX_DEBUG
  193.                 TF::PrintFunctionCall(i);
  194.             #endif
  195.            
  196.             j = TF::gs_Timers[i][e_iNumArguments];
  197.            
  198.            
  199.             TF::gs_iCurrentTimer = i;
  200.            
  201.             // Push the arguments
  202.             while (--j >= 0) {
  203.                 #emit CONST.alt   TF_gs_Timers
  204.                 #emit LOAD.S.pri  i
  205.                 #emit IDXADDR
  206.                 #emit MOVE.alt
  207.                 #emit LOAD.I
  208.                 #emit ADD
  209.                 #emit ADD.C       8 // e_axArguments * 4
  210.                 #emit MOVE.alt
  211.                 #emit LOAD.S.pri  j
  212.                 #emit IDXADDR
  213.                 #emit LOAD.I
  214.                 #emit PUSH.pri
  215.             }
  216.            
  217.             // Push the number of arguments
  218.             iArg = TF::gs_Timers[i][e_iNumArguments] * 4;
  219.            
  220.             #emit PUSH.S      iArg
  221.  
  222.             // Push the return address
  223.             #emit LCTRL       6
  224.             #emit ADD.C       28
  225.             #emit PUSH.pri
  226.  
  227.             // Call the function
  228.             #emit LOAD.S.pri  iFunc
  229.             #emit SCTRL       6
  230.            
  231.             #if TIMER_FIX_PERFORMANCE_CHECKS
  232.                 if (GetTickCount() - iTick > 10) {
  233.                     printf("(TimerFix) WARNING: The function \"%s\" took %dms to execute! This will affect other timers.", TF::gs_Timers[i][e_szFunctionName], GetTickCount() - iTick);
  234.                 }
  235.             #endif
  236.            
  237.             if (TF::gs_Timers[i][e_bIsRepeating])
  238.                 TF::gs_Timers[i][e_iNextCall] = GetTickCount() + TF::gs_Timers[i][e_iInterval] - 1;
  239.             else {
  240.                 TF::gs_Timers[i][e_bIsUsed] = false;
  241.                
  242.                 #if TIMER_FIX_DEBUG
  243.                     printf("(TimerFix) DEBUG: Timer %d (\"%s\") finished.", i, TF::gs_Timers[i][e_szFunctionName]);
  244.                 #endif
  245.             }
  246.            
  247.             TF::gs_iCurrentTimer = -1;
  248.         }
  249.     }
  250. }
  251.  
  252. stock TF::PrintFunctionCall(i) {
  253.     format(TF::gs_szDebugBuffer, sizeof(TF::gs_szDebugBuffer), "(TimerFix) DEBUG: Calling: %s(", TF::gs_Timers[i][e_szFunctionName]);
  254.    
  255.     for (new j = 0; j < TF::gs_Timers[i][e_iNumArguments]; j++) {
  256.         if (j)
  257.             strcat(TF::gs_szDebugBuffer, ", ");
  258.        
  259.         switch (TF::gs_Timers[i][e_aiArgumentTypes][j]) {
  260.             case 'f', 'F':
  261.                 format(TF::gs_szDebugBuffer, sizeof(TF::gs_szDebugBuffer), "%s%.2f", TF::gs_szDebugBuffer, TF::gs_Timers[i][e_axArguments][j]);
  262.            
  263.             default:
  264.                 format(TF::gs_szDebugBuffer, sizeof(TF::gs_szDebugBuffer), "%s%d", TF::gs_szDebugBuffer, TF::gs_Timers[i][e_axArguments][j]);
  265.         }
  266.     }
  267.    
  268.     strcat(TF::gs_szDebugBuffer, ")");
  269.    
  270.     print(TF::gs_szDebugBuffer);
  271. }
  272.  
  273. stock TF::GetPublicFunctionAddress(const szName[]) {
  274.     new
  275.         iIndex,
  276.         iTemp
  277.     ;
  278.    
  279.     if (-1 != (iIndex = funcidx(szName))) {
  280.         // Load the offset to DAT from the prefix
  281.         #emit LCTRL        1
  282.        
  283.         // Invert it so we have the offset to the prefix from DAT
  284.         #emit NEG
  285.        
  286.         // Copy it to alt for use later
  287.         #emit MOVE.alt
  288.        
  289.         // Add 32 to jump to the offset containing the public function's table
  290.         #emit ADD.C        32
  291.        
  292.         // Read the value there; must be done using LREF because
  293.         // it's outside of the DAT section
  294.         #emit STOR.S.pri   iTemp
  295.         #emit LREF.S.pri   iTemp
  296.        
  297.         // Add the value we just loaded to the prefix (that we stored in alt)
  298.         #emit ADD
  299.        
  300.         // Add index * 8 (each entry contains 2 cells - a pointer to the function's name
  301.         // and a pointer to the function itself, relative to COD).
  302.         #emit LOAD.S.alt   iIndex
  303.         #emit SHL.C.alt    3
  304.        
  305.         // Add that to the offset
  306.         #emit ADD
  307.        
  308.         // Now get the address it's pointing to. This seems to only work
  309.         // using LREF (as opposed to LOAD.I, for example).
  310.         #emit STOR.S.pri   iTemp
  311.         #emit LREF.S.pri   iTemp
  312.        
  313.         // Restore the stack
  314.         #emit STACK        8
  315.        
  316.         // Return the address
  317.         #emit RETN
  318.     }
  319.    
  320.     return 0;
  321. }
Advertisement
Add Comment
Please, Sign In to add comment