diff --git a/addons/sourcemod/configs/matchmodes.txt b/addons/sourcemod/configs/matchmodes.txt
index 03dd1de0f..a97a68049 100644
--- a/addons/sourcemod/configs/matchmodes.txt
+++ b/addons/sourcemod/configs/matchmodes.txt
@@ -27,11 +27,11 @@
{
"zonemod"
{
- "name" "ZoneMod 2.8.9b"
+ "name" "ZoneMod 2.8.9c"
}
"zoneretro"
{
- "name" "ZoneMod Retro 2.8.9b"
+ "name" "ZoneMod Retro 2.8.9c"
}
"zm3v3"
{
@@ -132,7 +132,7 @@
{
"zonehunters"
{
- "name" "ZoneHunters 2.8.9b"
+ "name" "ZoneHunters 2.8.9c"
}
"zh3v3"
{
diff --git a/addons/sourcemod/plugins/optional/autopause.smx b/addons/sourcemod/plugins/optional/autopause.smx
index 24c434ef9..b87c755d8 100644
Binary files a/addons/sourcemod/plugins/optional/autopause.smx and b/addons/sourcemod/plugins/optional/autopause.smx differ
diff --git a/addons/sourcemod/scripting/autopause.sp b/addons/sourcemod/scripting/autopause.sp
index 18879db20..27c8bcff1 100644
--- a/addons/sourcemod/scripting/autopause.sp
+++ b/addons/sourcemod/scripting/autopause.sp
@@ -18,173 +18,300 @@
You should have received a copy of the GNU General Public License along
with this program. If not, see .
*/
-#pragma semicolon 1
+
#pragma newdecls required
-#include
-#include
#include
+#include
+#include
#undef REQUIRE_PLUGIN
-#include "readyup"
+#include
+#include
+
+#define DEBUG_SM 1
+#define DEBUG_CHAT 2
+
+char sDebugMessage[256];
public Plugin myinfo =
{
- name = "L4D2 Auto-pause",
- author = "Darkid, Griffin",
- description = "When a player disconnects due to crash, automatically pause the game. When they rejoin, give them a correct spawn timer.",
- version = "2.1",
- url = "https://github.com/jbzdarkid/AutoPause"
+ name = "L4D2 Auto-pause",
+ author = "Darkid, Griffin, StarterX4",
+ description = "When a player disconnects due to crash, automatically pause the game. When they rejoin, give them a correct spawn timer.",
+ version = "2.2",
+ url = "https://github.com/SirPlease/L4D2-Competitive-Rework"
}
ConVar
- g_hCvarEnabled,
- g_hCvarForce,
- g_hCvarApdebug;
+ convarEnabled,
+ convarForce,
+ convarForceUnpause,
+ convarDebug;
+
Handle
- crashedPlayers,
- infectedPlayers,
- survivorPlayers;
+ crashedPlayers,
+ generalCrashers,
+ infectedPlayers,
+ survivorPlayers;
+
bool
- readyUpIsAvailable,
- RoundEnd;
+ bReadyUpIsAvailable,
+ bPauseIsAvailable,
+ bRoundEnd;
-public void OnPluginStart()
+public void OnPluginStart()
{
- LoadTranslations("autopause.phrases");
- // Suggestion by Nati: Disable for any 1v1
- g_hCvarEnabled = CreateConVar("autopause_enable", "1", "Whether or not to automatically pause when a player crashes.");
- g_hCvarForce = CreateConVar("autopause_force", "0", "Whether or not to force pause when a player crashes.");
- g_hCvarApdebug = CreateConVar("autopause_apdebug", "0", "Whether or not to debug information.");
-
- crashedPlayers = CreateTrie();
- infectedPlayers = CreateArray(64);
- survivorPlayers = CreateArray(64);
-
- HookEvent("round_start", RoundStart_Event);
- HookEvent("round_end", RoundEnd_Event);
- HookEvent("player_team", PlayerTeam_Event);
- HookEvent("player_disconnect", PlayerDisconnect_Event, EventHookMode_Pre);
+ convarEnabled = CreateConVar("autopause_enable", "1", "Whether or not to automatically pause when a player crashes.");
+ convarForce = CreateConVar("autopause_force", "0", "Whether or not to force pause when a player crashes.");
+ convarForceUnpause = CreateConVar("autopause_forceunpause", "0", "Whether or not we force unpause when the crashed players have loaded back in");
+ convarDebug = CreateConVar("autopause_apdebug", "0", "0: No Debugging - 1: Sourcemod Logs - 2: PrintToChat - 3: Both", _, true, 0.0, true, 3.0);
+
+ crashedPlayers = CreateTrie();
+ generalCrashers = CreateArray(64);
+ infectedPlayers = CreateArray(64);
+ survivorPlayers = CreateArray(64);
+
+ HookEvent("round_start", Event_RoundStart);
+ HookEvent("round_end", Event_RoundEnd);
+ HookEvent("player_team", Event_PlayerTeam);
+ HookEvent("player_disconnect", Event_PlayerDisconnect, EventHookMode_Pre);
}
public void OnAllPluginsLoaded()
{
- readyUpIsAvailable = LibraryExists("readyup");
+ bReadyUpIsAvailable = LibraryExists("readyup");
+ bPauseIsAvailable = LibraryExists("pause");
}
public void OnLibraryRemoved(const char[] name)
{
- if (StrEqual(name, "readyup")) readyUpIsAvailable = false;
+ if (strcmp(name, "readyup") == 0)
+ bReadyUpIsAvailable = false;
+
+ if (strcmp(name, "pause") == 0)
+ bPauseIsAvailable = false;
}
public void OnLibraryAdded(const char[] name)
{
- if (StrEqual(name, "readyup")) readyUpIsAvailable = true;
+ if (strcmp(name, "readyup") == 0)
+ bReadyUpIsAvailable = true;
+
+ if (strcmp(name, "pause") == 0)
+ bPauseIsAvailable = true;
}
-public void RoundStart_Event(Handle event, const char[] name, bool dontBroadcast)
+public void OnClientPutInServer(int client)
{
- ClearTrie(crashedPlayers);
- ClearArray(infectedPlayers);
- ClearArray(survivorPlayers);
- RoundEnd = false;
+ char sAuthId[64];
+ GetClientAuthId(client, AuthId_Steam2, sAuthId, sizeof(sAuthId));
+
+ if (strcmp(sAuthId, "BOT") == 0)
+ return;
+
+ int crasherIndex = FindStringInArray(generalCrashers, sAuthId);
+
+ if (crasherIndex == -1)
+ return;
+
+ RemoveFromArray(generalCrashers, crasherIndex);
+ int remainingCrashers = GetArraySize(generalCrashers);
+
+ if (convarDebug.BoolValue)
+ {
+ Format(sDebugMessage, sizeof(sDebugMessage), "[Autopause (OnClientPutInServer)] Crashed Player %s rejoined.", sAuthId);
+ DebugLog(sDebugMessage);
+ }
+
+ if (convarForceUnpause.BoolValue && bPauseIsAvailable && IsInPause())
+ {
+ if (!remainingCrashers)
+ {
+ CPrintToChatAll("{blue}[{default}AutoPause{blue}] {default}All {green}crashed {default}players have reconnected.. {blue}Unpausing{default}!");
+ ServerCommand("sm_forceunpause");
+
+ if (convarDebug.BoolValue)
+ {
+ Format(sDebugMessage, sizeof(sDebugMessage), "[Autopause (OnClientPutInServer)] All crashed players rejoined. Force Unpause was triggered.");
+ DebugLog(sDebugMessage);
+ }
+ }
+ else
+ CPrintToChatAll("{blue}[{default}AutoPause{blue}] {default}Waiting for {olive}%i {default}more {green}crashed {default}player%s {default}before automatic {blue}Unpause{default}!", remainingCrashers, remainingCrashers > 1 ? "s" : "");
+ }
}
-public void RoundEnd_Event(Handle event, const char[] name, bool dontBroadcast)
+public void Event_RoundStart(Event hEvent, char[] sEventName, bool dontBroadcast)
{
- RoundEnd = true;
+ ClearTrie(crashedPlayers);
+ ClearArray(generalCrashers);
+ ClearArray(infectedPlayers);
+ ClearArray(survivorPlayers);
+ bRoundEnd = false;
+}
+
+public void Event_RoundEnd(Event hEvent, char[] sEventName, bool dontBroadcast)
+{
+ bRoundEnd = true;
+}
+
+public void Event_PlayerTeam(Event hEvent, char[] sEventName, bool dontBroadcast)
+{
+ int client = GetClientOfUserId(hEvent.GetInt("userid"));
+
+ if (client <= 0 || client > MaxClients)
+ return;
+
+ char sAuthId[64];
+ GetClientAuthId(client, AuthId_Steam2, sAuthId, sizeof(sAuthId));
+
+ if (strcmp(sAuthId, "BOT") == 0)
+ return;
+
+ int survivorIndex = FindStringInArray(survivorPlayers, sAuthId);
+ int infectedIndex = FindStringInArray(infectedPlayers, sAuthId);
+
+ if (survivorIndex != -1)
+ {
+ RemoveFromArray(survivorPlayers, survivorIndex);
+
+ if (convarDebug.BoolValue)
+ {
+ Format(sDebugMessage, sizeof(sDebugMessage), "[AutoPause (%s)] Removed player %s from the survivor team.", sEventName, sAuthId);
+ DebugLog(sDebugMessage);
+ }
+ }
+
+ if (infectedIndex != -1)
+ {
+ RemoveFromArray(infectedPlayers, infectedIndex);
+
+ if (convarDebug.BoolValue)
+ {
+ Format(sDebugMessage, sizeof(sDebugMessage), "[AutoPause (%s)] Removed player %s from the infected team.", sEventName, sAuthId);
+ DebugLog(sDebugMessage);
+ }
+ }
+
+ int newTeam = hEvent.GetInt("team");
+
+ if (newTeam == L4D_TEAM_SURVIVOR)
+ {
+ PushArrayString(survivorPlayers, sAuthId);
+
+ if (convarDebug.BoolValue)
+ {
+ Format(sDebugMessage, sizeof(sDebugMessage), "[AutoPause (%s)] Added player %s to the survivor team.", sEventName, sAuthId);
+ DebugLog(sDebugMessage);
+ }
+ }
+ else if (newTeam == L4D_TEAM_INFECTED)
+ {
+ float fSpawnTime;
+
+ if (GetTrieValue(crashedPlayers, sAuthId, fSpawnTime))
+ {
+ CountdownTimer CTimer_SpawnTimer = L4D2Direct_GetSpawnTimer(client);
+ CTimer_Start(CTimer_SpawnTimer, fSpawnTime);
+ RemoveFromTrie(crashedPlayers, sAuthId);
+
+ if (convarDebug.BoolValue)
+ {
+ Format(sDebugMessage, sizeof(sDebugMessage), "[AutoPause (%s)] Player %s rejoined the infected, set spawn timer to %f.", sEventName, sAuthId, fSpawnTime);
+ DebugLog(sDebugMessage);
+ }
+ }
+
+ PushArrayString(infectedPlayers, sAuthId);
+
+ if (convarDebug.BoolValue)
+ {
+ Format(sDebugMessage, sizeof(sDebugMessage), "[AutoPause (%s)] Added player %s to the infected team.", sEventName, sAuthId);
+ DebugLog(sDebugMessage);
+ }
+ }
}
-// Handles players leaving and joining the infected team.
-public void PlayerTeam_Event(Event event, const char[] name, bool dontBroadcast)
+public void Event_PlayerDisconnect(Event hEvent, char[] sEventName, bool dontBroadcast)
{
- int client = GetClientOfUserId(GetEventInt(event, "userid"));
- if (client <= 0 || client > MaxClients) return;
- char steamId[64];
- GetClientAuthId(client, AuthId_Steam2, steamId, sizeof(steamId));
- if (strcmp(steamId, "BOT") == 0) return;
- int oldTeam = GetEventInt(event, "oldteam");
- int newTeam = GetEventInt(event, "team");
-
- int index = FindStringInArray(infectedPlayers, steamId);
- int survindex = FindStringInArray(infectedPlayers, steamId);
- if (oldTeam == 3)
- {
- if (index != -1) RemoveFromArray(infectedPlayers, index);
- if (GetConVarBool(g_hCvarApdebug)) LogMessage("[AutoPause] Removed player %s from infected team.", steamId);
- }
- else if (oldTeam == 2) {
- if (survindex != -1) RemoveFromArray(survivorPlayers, survindex);
- if (GetConVarBool(g_hCvarApdebug)) LogMessage("[AutoPause] Removed player %s from survivor team.", steamId);
- }
- if (newTeam == 3)
- {
- float spawnTime;
- if (GetTrieValue(crashedPlayers, steamId, spawnTime))
- {
- CountdownTimer spawnTimer = L4D2Direct_GetSpawnTimer(client);
- CTimer_Start(spawnTimer, spawnTime);
- RemoveFromTrie(crashedPlayers, steamId);
- LogMessage("[AutoPause] Player %s rejoined, set spawn timer to %f.", steamId, spawnTime);
- }
- else if (index == -1) {
- PushArrayString(infectedPlayers, steamId);
- if (GetConVarBool(g_hCvarApdebug)) LogMessage("[AutoPause] Added player %s to infected team.", steamId);
- }
- }
- else if (newTeam == 2 && survindex == -1) {
- PushArrayString(survivorPlayers, steamId);
- if (GetConVarBool(g_hCvarApdebug)) LogMessage("[AutoPause] Added player %s to survivor team.", steamId);
- }
+ int client = GetClientOfUserId(hEvent.GetInt("userid"));
+
+ if (client <= 0 || client > MaxClients)
+ return;
+
+ char sAuthId[64];
+ GetClientAuthId(client, AuthId_Steam2, sAuthId, sizeof(sAuthId));
+
+ if (strcmp(sAuthId, "BOT") == 0)
+ return;
+
+ if (FindStringInArray(infectedPlayers, sAuthId) == -1 && FindStringInArray(survivorPlayers, sAuthId) == -1)
+ return;
+
+ if (GetClientTeam(client) == L4D_TEAM_SURVIVOR && !IsPlayerAlive(client))
+ {
+ if (convarDebug.BoolValue)
+ {
+ Format(sDebugMessage, sizeof(sDebugMessage), "[AutoPause (%s)] Player %N left the game but is a dead Survivor", sEventName, client);
+ DebugLog(sDebugMessage);
+ }
+ return;
+ }
+
+ char sReason[128];
+ hEvent.GetString("reason", sReason, sizeof(sReason));
+
+ char sTimedOut[64];
+ Format(sTimedOut, sizeof(sTimedOut), "%N timed out", client);
+
+ if (convarDebug.BoolValue)
+ {
+ Format(sDebugMessage, sizeof(sDebugMessage), "[AutoPause (%s)] Player %N (%s) left the game: %s", sEventName, client, sAuthId, sReason);
+ DebugLog(sDebugMessage);
+ }
+
+ if (strcmp(sReason, sTimedOut) == 0 || strcmp(sReason, "No Steam logon") == 0)
+ {
+ if (convarEnabled.BoolValue && (!bReadyUpIsAvailable || !IsInReady()) && !bRoundEnd)
+ {
+ if (convarForce.BoolValue)
+ ServerCommand("sm_forcepause");
+ else
+ FakeClientCommand(client, "sm_pause");
+
+ if (FindStringInArray(generalCrashers, sAuthId) == -1)
+ PushArrayString(generalCrashers, sAuthId);
+
+ CPrintToChatAll("{blue}[{default}AutoPause{blue}] {olive}%N {default}crashed.", client);
+ }
+ }
+
+ if (FindStringInArray(infectedPlayers, sAuthId) != -1)
+ {
+ CountdownTimer CTimer_SpawnTimer = L4D2Direct_GetSpawnTimer(client);
+ if (CTimer_SpawnTimer != CTimer_Null)
+ {
+ float fTimeLeft = CTimer_GetRemainingTime(CTimer_SpawnTimer);
+
+ if (convarDebug.BoolValue)
+ {
+ Format(sDebugMessage, sizeof(sDebugMessage), "[AutoPause (%s)] Player %s left the game with %f time until spawn.", sEventName, sAuthId, fTimeLeft);
+ DebugLog(sDebugMessage);
+ }
+
+ SetTrieValue(crashedPlayers, sAuthId, fTimeLeft);
+ }
+ }
}
-public void PlayerDisconnect_Event(Event hEvent, const char[] name, bool dontBroadcast)
+void DebugLog(char[] sMessage)
{
- int client = GetClientOfUserId(GetEventInt(hEvent, "userid"));
- if (client <= 0 || client > MaxClients) return;
- char steamId[64];
- GetClientAuthId(client, AuthId_Steam2, steamId, sizeof(steamId));
- if (strcmp(steamId, "BOT") == 0) return;
-
- // Player wasn't actually a gamer, ignore
- if (FindStringInArray(infectedPlayers, steamId) == -1 && FindStringInArray(survivorPlayers, steamId) == -1) return;
-
- char reason[128];
- GetEventString(hEvent, "reason", reason, sizeof(reason));
- char playerName[128];
- GetEventString(hEvent, "name", playerName, sizeof(playerName));
- char timedOut[256];
- Format(timedOut, sizeof(timedOut), "%s timed out", playerName);
-
- if (GetConVarBool(g_hCvarApdebug)) LogMessage("[AutoPause] Player %s (%s) left the game: %s", playerName, steamId, reason);
-
- // If the leaving player crashed, pause.
- if (strcmp(reason, timedOut) == 0 || strcmp(reason, "No Steam logon") == 0)
- {
- if ((!readyUpIsAvailable || !IsInReady()) && !RoundEnd && GetConVarBool(g_hCvarEnabled))
- {
- if (GetConVarBool(g_hCvarForce))
- {
- ServerCommand("sm_forcepause");
- }
- else
- {
- FakeClientCommand(client, "sm_pause");
- }
- CPrintToChatAll("%t %t", "Tag", "crashed", playerName);
- }
- }
-
- // If the leaving player was on infected, save their spawn timer.
- if (FindStringInArray(infectedPlayers, steamId) != -1)
- {
- float timeLeft;
- CountdownTimer spawnTimer = L4D2Direct_GetSpawnTimer(client);
- if (spawnTimer != CTimer_Null)
- {
- timeLeft = CTimer_GetRemainingTime(spawnTimer);
- LogMessage("[AutoPause] Player %s left the game with %f time until spawn.", steamId, timeLeft);
- SetTrieValue(crashedPlayers, steamId, timeLeft);
- }
- }
+ int flags = convarDebug.IntValue;
+
+ if (flags & DEBUG_SM)
+ LogMessage(sMessage);
+
+ if (flags & DEBUG_CHAT)
+ PrintToChatAll(sMessage);
}
\ No newline at end of file
diff --git a/cfg/cfgogl/zh1v1/confogl.cfg b/cfg/cfgogl/zh1v1/confogl.cfg
index 6a12227c1..e07554963 100644
--- a/cfg/cfgogl/zh1v1/confogl.cfg
+++ b/cfg/cfgogl/zh1v1/confogl.cfg
@@ -7,7 +7,7 @@
// =======================================================================================
// ReadyUp Cvars
-l4d_ready_cfg_name "1v1 [Zone]Hunters v2.8.9b"
+l4d_ready_cfg_name "1v1 [Zone]Hunters v2.8.9c"
// Confogl Cvars
confogl_addcvar mp_gamemode "versus" // Force Versus for the config.
diff --git a/cfg/cfgogl/zh2v2/confogl.cfg b/cfg/cfgogl/zh2v2/confogl.cfg
index b27d3c824..d11a8bde2 100644
--- a/cfg/cfgogl/zh2v2/confogl.cfg
+++ b/cfg/cfgogl/zh2v2/confogl.cfg
@@ -7,7 +7,7 @@
// =======================================================================================
// ReadyUp Cvars
-l4d_ready_cfg_name "2v2 [Zone]Hunters v2.8.9b"
+l4d_ready_cfg_name "2v2 [Zone]Hunters v2.8.9c"
// Confogl Cvars
confogl_addcvar mp_gamemode "versus" // Force Versus for the config.
diff --git a/cfg/cfgogl/zh3v3/confogl.cfg b/cfg/cfgogl/zh3v3/confogl.cfg
index 925e38f96..dc28d7081 100644
--- a/cfg/cfgogl/zh3v3/confogl.cfg
+++ b/cfg/cfgogl/zh3v3/confogl.cfg
@@ -7,7 +7,7 @@
// =======================================================================================
// ReadyUp Cvars
-l4d_ready_cfg_name "3v3 [Zone]Hunters v2.8.9b"
+l4d_ready_cfg_name "3v3 [Zone]Hunters v2.8.9c"
// Confogl Cvars
confogl_addcvar mp_gamemode "versus" // Force Versus for the config.
diff --git a/cfg/cfgogl/zm1v1/confogl.cfg b/cfg/cfgogl/zm1v1/confogl.cfg
index 1d1a3622c..f98828782 100644
--- a/cfg/cfgogl/zm1v1/confogl.cfg
+++ b/cfg/cfgogl/zm1v1/confogl.cfg
@@ -8,7 +8,7 @@
// =======================================================================================
// ReadyUp Cvars
-l4d_ready_cfg_name "1v1 Zonemod v2.8.9b"
+l4d_ready_cfg_name "1v1 Zonemod v2.8.9c"
// Confogl Cvars
confogl_addcvar mp_gamemode "versus" // Force Versus for the config.
diff --git a/cfg/cfgogl/zm2v2/confogl.cfg b/cfg/cfgogl/zm2v2/confogl.cfg
index ff3ce7022..e4c48f4f6 100644
--- a/cfg/cfgogl/zm2v2/confogl.cfg
+++ b/cfg/cfgogl/zm2v2/confogl.cfg
@@ -8,7 +8,7 @@
// =======================================================================================
// ReadyUp Cvars
-l4d_ready_cfg_name "2v2 Zonemod v2.8.9b"
+l4d_ready_cfg_name "2v2 Zonemod v2.8.9c"
// Confogl Cvars
confogl_addcvar mp_gamemode "versus" // Force Versus for the config.
diff --git a/cfg/cfgogl/zm3v3/confogl.cfg b/cfg/cfgogl/zm3v3/confogl.cfg
index 02ac843ce..079cda6dd 100644
--- a/cfg/cfgogl/zm3v3/confogl.cfg
+++ b/cfg/cfgogl/zm3v3/confogl.cfg
@@ -8,7 +8,7 @@
// =======================================================================================
// ReadyUp Cvars
-l4d_ready_cfg_name "3v3 Zonemod v2.8.9b"
+l4d_ready_cfg_name "3v3 Zonemod v2.8.9c"
// Confogl Cvars
confogl_addcvar mp_gamemode "versus" // Force Versus for the config.
diff --git a/cfg/cfgogl/zonehunters/confogl.cfg b/cfg/cfgogl/zonehunters/confogl.cfg
index 6b03cd945..6e3b8f2d8 100644
--- a/cfg/cfgogl/zonehunters/confogl.cfg
+++ b/cfg/cfgogl/zonehunters/confogl.cfg
@@ -7,7 +7,7 @@
// =======================================================================================
// ReadyUp Cvars
-l4d_ready_cfg_name "[Zone]Hunters v2.8.9b"
+l4d_ready_cfg_name "[Zone]Hunters v2.8.9c"
// Confogl Cvars
confogl_addcvar mp_gamemode "versus" // Force Versus for the config.
diff --git a/cfg/cfgogl/zonemod/confogl.cfg b/cfg/cfgogl/zonemod/confogl.cfg
index 4a9877ffc..6a9c0d2bb 100644
--- a/cfg/cfgogl/zonemod/confogl.cfg
+++ b/cfg/cfgogl/zonemod/confogl.cfg
@@ -8,7 +8,7 @@
// =======================================================================================
// ReadyUp Cvars
-l4d_ready_cfg_name "ZoneMod v2.8.9b"
+l4d_ready_cfg_name "ZoneMod v2.8.9c"
// Confogl Cvars
confogl_addcvar mp_gamemode "versus" // Force Versus for the config.
diff --git a/cfg/cfgogl/zoneretro/confogl.cfg b/cfg/cfgogl/zoneretro/confogl.cfg
index 605bb8ab5..ec60c8fd8 100644
--- a/cfg/cfgogl/zoneretro/confogl.cfg
+++ b/cfg/cfgogl/zoneretro/confogl.cfg
@@ -8,7 +8,7 @@
// =======================================================================================
// ReadyUp Cvars
-l4d_ready_cfg_name "ZoneMod Retro v2.8.9b"
+l4d_ready_cfg_name "ZoneMod Retro v2.8.9c"
// Confogl Cvars
confogl_addcvar mp_gamemode "versus" // Force Versus for the config.