Advertisement
Mauzen

RNPC Pool 1.0

Jul 3rd, 2014
760
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Pawn 7.27 KB | None | 0 0
  1. // NPC Pool stuff
  2. // The NPC pool will provide a set of connected and ready NPCs that can
  3. // be used for various different roles that require a short reaction time.
  4. // By having the NPCs already connected, there is no delay for connecting
  5. // and spawning them. So whenever you need a NPC with a certain role, you
  6. // pick the ID of an idle one from the pool, and teleport him to where he is
  7. // needed
  8.  
  9. // Version 1.0, Mauzen, 2.7.2014
  10.  
  11. // Avoid including the pool twice
  12. #if defined _rnpcpool_included
  13.     #endinput
  14. #endif
  15. #define _rnpcpool_included
  16.  
  17. #tryinclude <rnpc>
  18.  
  19. // Initialize NPC pool if it doesnt exist yet
  20. // Define size only if it isnt defined yet, so people may define it in their own script
  21. #if !defined RNPC_POOL_MAXSIZE
  22.     #define RNPC_POOL_MAXSIZE               50          // Maximum amount of NPCs available for the pool
  23. #endif
  24. #if !defined RNPC_POOL_STARTSIZE
  25.     #define RNPC_POOL_STARTSIZE             10          // Default pool size when starting
  26. #endif
  27.  
  28. #define RNPC_POOL_ROLE_IDLE                 -1
  29. #define RNPC_POOL_ROLE_RESET_PENDING        -2
  30. #define RNPC_POOL_ROLE_UNUSED               -3
  31.  
  32.  
  33.  
  34. // Forward the callback
  35. forward OnRNPCPoolFull(curSize, maxSize);
  36.  
  37.  
  38. // Prepare pool data
  39. enum RNPC_POOL_ENUM {
  40.     RNPC_POOL_ID,       // ID of the NPC in the pool
  41.     RNPC_POOL_ROLE      // The current role of the NPC
  42.                         // When creating your own roles, you must care for the ID to be unique
  43. };
  44. new rnpcPool[RNPC_POOL_MAXSIZE][RNPC_POOL_ENUM];
  45.  
  46. new curPoolSize = 0;            // Current size of the NPC pool
  47.  
  48. // This function returns the PLAYERID of an idle NPC from the pool,
  49. // or INVALID_PLAYER_ID if theres no idle NPC
  50. stock PickRNPCFromPool(fortask) {
  51.     // Negative task IDs are used internally, not allowed for manual use
  52.     if (fortask < 0) return INVALID_PLAYER_ID;
  53.    
  54.     for (new i = 0; i < RNPC_POOL_MAXSIZE; i++) {
  55.         // Check if the NPC is idle, and marked as completely connected
  56.         if (rnpcPool[i][RNPC_POOL_ROLE] == RNPC_POOL_ROLE_IDLE &&(rnpcPend{i} & RNPC_CONNECTED)) {
  57.             // Idle NPC found, set his new role
  58.             rnpcPool[i][RNPC_POOL_ROLE] = fortask;
  59.             // And return his playerid
  60.             return rnpcPool[i][RNPC_POOL_ID];          
  61.         }
  62.     }
  63.     // Call a callback that might try to resolve the problem
  64.     CallRemoteFunction("OnRNPCPoolFull", "ii", curPoolSize, RNPC_POOL_MAXSIZE);
  65.     // No idle NPC found
  66.     return INVALID_PLAYER_ID;
  67. }
  68.  
  69. // Sets a NPC back to idle state
  70. // This stops all playbacks, and puts the NPC far away so
  71. // he doesnt stream in for others to reduce unneccessary traffic
  72. // see OnRNPCPlaybackStopped for part 2
  73. stock ReturnRNPCToPool(npcid) {
  74.     // Get the pool ID
  75.     new slot = RNPCPoolIDFromPlayerID(npcid);
  76.     // Abort if the npcid isnt in the pool
  77.     if (slot == -1) return 0;
  78.    
  79.     // Set the role to a "pending for reset" state,
  80.     // so the NPC doesnt get a new role until he is fully reset
  81.     rnpcPool[slot][RNPC_POOL_ROLE] = RNPC_POOL_ROLE_RESET_PENDING;
  82.    
  83.     // Stop playback
  84.     // This doesnt stop him instantly, wait for OnRNPCPlaybackStopped
  85.     RNPC_StopPlayback(npcid);  
  86.     return 1;
  87. }
  88.  
  89. // Sets the current size of the pool
  90. // Either kicking NPCs or connecting new ones
  91. // If noactivekick is true, it will kick only inactive NPCs, and so eventually not
  92. // reducing the pool to the desired new size
  93. // Else it will start kicking inactives, and then kicks the NPCs with the highest pool ID
  94. // Returns the new pool size
  95. stock SetRNPCPoolSize(newsize, noactivekick=1) {
  96.    
  97.     // Limited by the maximum pool size
  98.     if (newsize > RNPC_POOL_MAXSIZE) newsize = RNPC_POOL_MAXSIZE;
  99.     // And by 0
  100.     if (newsize < 0) newsize = 0;
  101.    
  102.     // Increasing the pool size, connect new NPCs
  103.     if (newsize > curPoolSize) {
  104.         new name[MAX_PLAYER_NAME];     
  105.        
  106.         // Find unused NPC slots and connect them
  107.         for (new i = 0; i < RNPC_POOL_MAXSIZE; i++) {
  108.             if (rnpcPool[i][RNPC_POOL_ROLE] == RNPC_POOL_ROLE_UNUSED) {
  109.                 // Connect a new NPC and prepare it to be added to the pool
  110.                 format(name, sizeof(name), "Pool_RNPC_%d", i);
  111.                 rnpcPool[i][RNPC_POOL_ID] = ConnectRNPC(name);
  112.                 rnpcPool[i][RNPC_POOL_ROLE] = RNPC_POOL_ROLE_IDLE;
  113.                 // Increase pool size by 1
  114.                 curPoolSize++;
  115.             }
  116.             // Stop when there are enough NPCs
  117.             if (curPoolSize == newsize) break;
  118.         }
  119.         return curPoolSize;
  120.     }
  121.    
  122.     // Reduce the pool size
  123.     if (newsize < curPoolSize) {       
  124.        
  125.         // First loop removing idle NPCs only, starting at the last index
  126.         for (new i = RNPC_POOL_MAXSIZE-1; i >= 0; i--) {
  127.             if (rnpcPool[i][RNPC_POOL_ROLE] == RNPC_POOL_ROLE_IDLE) {              
  128.                 Kick(i);
  129.                 rnpcPool[i][RNPC_POOL_ROLE] = RNPC_POOL_ROLE_UNUSED;
  130.                 rnpcPool[i][RNPC_POOL_ID] = INVALID_PLAYER_ID;
  131.                 curPoolSize--;
  132.             }
  133.             // Enough NPCs removed, return
  134.             if (curPoolSize == newsize) return curPoolSize;
  135.         }
  136.        
  137.         // Not enough idle NPCs removed, only do that if kicking actives is enabled
  138.         if (!noactivekick) {
  139.             for (new i = RNPC_POOL_MAXSIZE-1; i >= 0; i--) {
  140.                 Kick(i);
  141.                 rnpcPool[i][RNPC_POOL_ROLE] = RNPC_POOL_ROLE_UNUSED;
  142.                 rnpcPool[i][RNPC_POOL_ID] = INVALID_PLAYER_ID;
  143.                 curPoolSize--;
  144.                 // Enough NPCs removed, return
  145.                 if (curPoolSize == newsize) return curPoolSize;
  146.             }
  147.         }
  148.     }
  149.    
  150.     return curPoolSize;
  151. }
  152.  
  153.  
  154. // Returns the index in the pool array from the playerid,
  155. // or -1 if it isnt in the pool
  156. stock RNPCPoolIDFromPlayerID(npcid) {
  157.     for (new i = 0; i < RNPC_POOL_MAXSIZE; i++) {
  158.         // playerid matches
  159.         if (rnpcPool[i][RNPC_POOL_ID] == npcid) return i;
  160.     }
  161.     // No match found
  162.     return -1;
  163. }
  164.  
  165.  
  166. // Returns the current role of a NPC from the pool
  167. // or -1 if it isnt a NPC, or its not part of the pool or got no task
  168. stock GetPoolRNPCRole(npcid) {
  169.     new slot = RNPCPoolIDFromPlayerID(npcid);
  170.     if (slot == -1) return -1;
  171.     return rnpcPool[slot][RNPC_POOL_ROLE];
  172. }
  173.  
  174.  
  175. // Hook OnGameModeInit to connect the pool NPCs on start
  176. // and prepare data
  177. public OnGameModeInit() {
  178.  
  179.     // Set all pool slots to unused for initialisation
  180.     for (new i = 0; i < RNPC_POOL_MAXSIZE; i++) {
  181.         rnpcPool[i][RNPC_POOL_ID] = INVALID_PLAYER_ID;
  182.         rnpcPool[i][RNPC_POOL_ROLE] = RNPC_POOL_ROLE_UNUSED;
  183.     }
  184.    
  185.     // Set the pool to the default starting size
  186.     SetRNPCPoolSize(RNPC_POOL_STARTSIZE);
  187.  
  188.     #if defined RNPCPOOL_OnGameModeInit
  189.         return RNPCPOOL_OnGameModeInit();
  190.     #else
  191.         return 1;
  192.     #endif
  193. }
  194. #if defined _ALS_OnGameModeInit
  195.     #undef OnGameModeInit
  196. #else
  197.     #define _ALS_OnGameModeInit
  198. #endif
  199. #define OnGameModeInit RNPCPOOL_OnGameModeInit
  200. forward RNPCPOOL_OnGameModeInit();
  201.  
  202. // Hook OnRNPCPlaybackStopped to set NPCs idle correctly
  203. public OnRNPCPlaybackStopped(npcid) {
  204.     new slot = RNPCPoolIDFromPlayerID(npcid);
  205.    
  206.     // Only do this for RNPCs in the pool with a pending reset
  207.     if (slot > -1) {
  208.         if (rnpcPool[slot][RNPC_POOL_ROLE] == RNPC_POOL_ROLE_RESET_PENDING) {
  209.             // Reset NPC to idle role
  210.             rnpcPool[slot][RNPC_POOL_ROLE] = RNPC_POOL_ROLE_IDLE;
  211.             // Teleport him out of the usual range to avoid unneeded stream-ins
  212.             SetPlayerPos(npcid, 0.0, 0.0, -300.0);
  213.             // Reset the NPC name
  214.             new name[MAX_PLAYER_NAME];
  215.             format(name, sizeof(name), "Pool_RNPC_%d", slot);
  216.             SetPlayerName(npcid, name);
  217.         }
  218.     }
  219.  
  220.     #if defined RNPCPOOL_OnRNPCPlaybackStopped
  221.         RNPCPOOL_OnRNPCPlaybackStopped(npcid);
  222.     #else
  223.         return;
  224.     #endif
  225. }
  226. #if defined _ALS_OnRNPCPlaybackStopped
  227.     #undef OnRNPCPlaybackStopped
  228. #else
  229.     #define _ALS_OnRNPCPlaybackStopped
  230. #endif
  231. #define OnRNPCPlaybackStopped RNPCPOOL_OnRNPCPlaybackStopped
  232. forward RNPCPOOL_OnRNPCPlaybackStopped(npcid);
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement