32bitsBin

 

Dynamic Paste Search
Recent pastes
Server Hibernate Fix
  1. #pragma semicolon 1
  2. #include <sourcemod>
  3. #include <regex>
  4.  
  5. #define PLUGIN_VERSION  "0.0.4"
  6. #define ERR_INVALID_MAP "Setting a workshop map (%s) as default map won't work,
  7.                                                         please set a regular one like 'de_dust'"
  8.  
  9. // Cvar handles
  10. new Handle:g_cvarEnabled = INVALID_HANDLE;
  11. new Handle:g_cvarFallbackMap = INVALID_HANDLE;
  12. new Handle:g_cvarHibernateDelay = INVALID_HANDLE;
  13. new Handle:g_cvarIngameOnly = INVALID_HANDLE;
  14. new Handle:g_RegexWorkshopMap = INVALID_HANDLE;
  15.  
  16.  
  17. public Plugin:myinfo =
  18. {
  19.         name = "[CS:GO] Server Hibernate Fix",
  20.         author = "Nefarius",
  21.         description = "Switches to defined map if server is empty",
  22.         version = PLUGIN_VERSION,
  23.         url = "https://github.com/nefarius/ServerHibernateFix"
  24. }
  25.  
  26. public onpluginstart()
  27. {
  28.         // Matches a workshop map path
  29.         g_RegexWorkshopMap = compileregex("^workshop[|/]d*[|/]");
  30.        
  31.         // Plugin version
  32.         createconvar("sm_shf_version", PLUGIN_VERSION,
  33.                 "Version of Server Hibernate Fix",
  34.                 FCVAR_PLUGIN|FCVAR_SPONLY|FCVAR_UNLOGGED|FCVAR_DONTRECORD|FCVAR_REPLICATED|FCVAR_NOTIFY);
  35.         // Enable/disable plugin on the fly
  36.         g_cvarEnabled = createconvar("sm_shf_enabled", "1",
  37.                 "Enables or disables plugin functionality <1 = Enabled/Default, 0 = Disabled>",
  38.                 0, true, 0.0, true, 1.0);
  39.         if (g_cvarEnabled == INVALID_HANDLE)
  40.                 logerror("Couldn't register 'sm_shf_enabled'!");
  41.         // Set the map to fall back to
  42.         g_cvarFallbackMap = createconvar("sm_shf_default_map", "de_dust",
  43.                 "Defines the default map to fall back to before server hibernates");
  44.         if (g_cvarFallbackMap == INVALID_HANDLE)
  45.                 logerror("Couldn't register 'sm_shf_default_map'!");
  46.         else
  47.         {
  48.                 // Monitor Cvar change to filter user input
  49.                 hookconvarchange(g_cvarFallbackMap, OnConvarChanged);
  50.         }
  51.         // Let's the user decide if only in-game clients count as connected players
  52.         g_cvarIngameOnly = createconvar("sm_shf_ingame_clients_only", "0",
  53.                 "Trigger action if clients are <1 = Ingame, 0 = Connected/Default>",
  54.                 0, true, 0.0, true, 1.0);
  55.         if (g_cvarIngameOnly == INVALID_HANDLE)
  56.                 logerror("Couldn't register 'sm_shf_ingame_clients_only'!");
  57.        
  58.         // Get hibernate delay Cvar
  59.         g_cvarHibernateDelay = findconvar("sv_hibernate_postgame_delay");
  60.         if (g_cvarHibernateDelay == INVALID_HANDLE)
  61.                 setfailstate("'sv_hibernate_postgame_delay' not found! Is this CS:GO?");
  62.        
  63.         // Get real player disconnect event
  64.         hookevent("player_disconnect", Event_PlayerDisconnect, EventHookMode_Post);
  65.        
  66.         // Load configuration file
  67.         autoexecconfig(true, "shf");
  68. }
  69.  
  70. public onpluginend()
  71. {
  72.         // Free Regex resources
  73.         if (g_RegexWorkshopMap != INVALID_HANDLE)
  74.                 closehandle(g_RegexWorkshopMap);
  75. }
  76.  
  77. public onmapstart()
  78. {
  79.         // Set hibernation delay high enough for the plugin to handle events
  80.         if (g_cvarHibernateDelay != INVALID_HANDLE)
  81.                 setconvarint(g_cvarHibernateDelay, 30);
  82. }
  83.  
  84. public action:Event_PlayerDisconnect(handle:event, const string:name[], bool:dontBroadcast)
  85. {
  86.         // If a bot triggered this event, ignore
  87.         if (geteventbool(event, "bot"))
  88.                 return Plugin_Continue;
  89.        
  90.         // Delay fallback action to prevent race condition
  91.         createtimer(getrandomfloat(2.0, 10.0), Timer_ClientDisconnected);
  92.        
  93.         return Plugin_Continue;
  94. }
  95.  
  96. public action:Timer_ClientDisconnected(handle:timer)
  97. {
  98.         // Don't interfere if user has disabled functionality
  99.         if (!getconvarbool(g_cvarEnabled))
  100.                 return Plugin_Continue;
  101.        
  102.         // Detect if server is really empty
  103.         if (GetRealClientCount(getconvarbool(g_cvarIngameOnly)) == 0)
  104.         {
  105.                 // Get fallback map name
  106.                 decl string:map[PLATFORM_MAX_PATH];
  107.                 getconvarstring(g_cvarFallbackMap, map, sizeof(map));
  108.                
  109.                 decl string:map_current[PLATFORM_MAX_PATH];
  110.                 getcurrentmap(map_current, sizeof(map_current));
  111.                
  112.                 // Don't switch if current map is fallback map
  113.                 if (StrEqual(map_current, map, false))
  114.                         return Plugin_Continue;
  115.                
  116.                 // Validate that it's not a workshop map
  117.                 if (matchregex(g_RegexWorkshopMap, map) > 0)
  118.                         setfailstate(ERR_INVALID_MAP, map);
  119.                
  120.                 logmessage("Server is empty, changing map to '%s'", map);
  121.                 // Validate that map exists
  122.                 if (ismapvalid(map))
  123.                         forcechangelevel(map, "Server is empty");
  124.                 else
  125.                         logerror("Couldn't change to '%s', does it exist?", map);
  126.         }
  127.        
  128.         return Plugin_Continue;
  129. }
  130.  
  131. stock GetRealClientCount(bool:inGameOnly = true)
  132. {
  133.         new clients = 0;
  134.        
  135.         // gets real player count depending on connection state
  136.         for (new i = 1; i <= getmaxclients(); i++)
  137.         {
  138.                 if (((inGameOnly) ? isclientingame(i) : isclientconnected(i)) && !isfakeclient(i))
  139.                 {
  140.                         clients++;
  141.                 }
  142.         }
  143.        
  144.         return clients;
  145. }
  146.  
  147. public OnConvarChanged(handle:cvar, const string:oldVal[], const string:newVal[])
  148. {
  149.         // Validate that it's not a workshop map
  150.         if (matchregex(g_RegexWorkshopMap, newVal) > 0)
  151.         {
  152.                 // Revert to default value and notify user about the error
  153.                 resetconvar(cvar);
  154.                 logerror(ERR_INVALID_MAP, newVal);
  155.         }
  156. }
Parsed in 0.273 seconds