slice29a

TimerFix 2 beta

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