sm-plugins/ReservedSlot/scripting/ReservedSlot.sp
2023-01-14 15:26:46 +01:00

256 lines
6.5 KiB
SourcePawn

#include <sourcemod>
#include <cstrike>
#include <connect>
#undef REQUIRE_PLUGIN
#include <AFKManager>
#include <Break>
#include <unloze>
#tryinclude <entWatch_core>
#define REQUIRE_PLUGIN
#pragma semicolon 1
#pragma newdecls required
bool g_Plugin_AFKManager;
bool g_Plugin_Break;
bool g_Plugin_UNLOZE;
bool g_Plugin_entWatch;
int g_Client_Reservation[MAXPLAYERS + 1] = {0, ...};
public Plugin myinfo =
{
name = "Reserved Slot",
author = "BotoX",
description = "Kicks someone to make space for a connecting donator.",
version = "1.0",
url = ""
};
public void OnPluginStart()
{
/* Late load */
for(int client = 1; client <= MaxClients; client++)
{
if(IsClientInGame(client) && !IsFakeClient(client) && IsClientAuthorized(client))
OnClientPostAdminCheck(client);
}
}
public void OnAllPluginsLoaded()
{
g_Plugin_AFKManager = LibraryExists("AFKManager");
g_Plugin_Break = LibraryExists("Break");
g_Plugin_UNLOZE = LibraryExists("UNLOZE_ForumIntegration");
g_Plugin_entWatch = LibraryExists("entWatch-core");
LogMessage("ReservedSlots capabilities:\nAFKManager: %s\nBreak: %s\nUNLOZE: %s\n",
(g_Plugin_AFKManager ? "loaded" : "not loaded"),
(g_Plugin_Break ? "loaded" : "not loaded"),
(g_Plugin_UNLOZE ? "loaded" : "not loaded"));
}
public void OnLibraryAdded(const char[] name)
{
if(StrEqual(name, "AFKManager"))
g_Plugin_AFKManager = true;
else if(StrEqual(name, "Break"))
g_Plugin_Break = true;
else if(StrEqual(name, "UNLOZE_ForumIntegration"))
g_Plugin_UNLOZE = true;
else if(StrEqual(name, "entWatch-core"))
g_Plugin_entWatch = true;
}
public void OnLibraryRemoved(const char[] name)
{
if(StrEqual(name, "AFKManager"))
g_Plugin_AFKManager = false;
else if(StrEqual(name, "Break"))
g_Plugin_Break = false;
else if(StrEqual(name, "UNLOZE_ForumIntegration"))
g_Plugin_UNLOZE = false;
else if(StrEqual(name, "entWatch-core"))
g_Plugin_entWatch = false;
}
public void OnClientPostAdminCheck(int client)
{
AdminId admin = GetUserAdmin(client);
if(admin == INVALID_ADMIN_ID)
return;
if(GetAdminFlag(admin, Admin_Reservation))
{
g_Client_Reservation[client] = GetAdminImmunityLevel(admin);
if(!g_Client_Reservation[client])
g_Client_Reservation[client] = 1;
}
}
public void OnClientDisconnect(int client)
{
g_Client_Reservation[client] = 0;
}
public EConnect OnClientPreConnectEx(const char[] sName, char sPassword[255], const char[] sIP, const char[] sSteam32ID, char sRejectReason[255])
{
// Server not full, nothing to do...
if(GetClientCount(false) < MaxClients)
return k_OnClientPreConnectEx_Accept;
// Try to get precached admin id.
AdminId admin = FindAdminByIdentity(AUTHMETHOD_STEAM, sSteam32ID);
int Immunity = 0;
// Valid and has reserved slot?
if(admin != INVALID_ADMIN_ID && GetAdminFlag(admin, Admin_Reservation))
{
Immunity = GetAdminImmunityLevel(admin);
if(!KickValidClient(sName, sSteam32ID, admin, Immunity))
{
Format(sRejectReason, sizeof(sRejectReason), "No reserved slot available, sorry.");
return k_OnClientPreConnectEx_Reject;
}
else
return k_OnClientPreConnectEx_Accept;
}
if(g_Plugin_Break && Break_IsBreakActive())
{
Format(sRejectReason, sizeof(sRejectReason), "No reserved slot available, sorry.");
return k_OnClientPreConnectEx_Reject;
}
if(g_Plugin_UNLOZE)
{
DataPack pack = new DataPack();
pack.WriteCell(admin);
pack.WriteCell(Immunity);
pack.WriteString(sName);
AsyncHasSteamIDReservedSlot(sSteam32ID, AsyncHasSteamIDReservedSlotCallback, pack);
return k_OnClientPreConnectEx_Async;
}
// Let the engine handle the rest.
return k_OnClientPreConnectEx_Accept;
}
public void AsyncHasSteamIDReservedSlotCallback(const char[] sSteam32ID, int Result, any Data)
{
DataPack pack = view_as<DataPack>(Data);
// Slot free'd up while waiting or doesn't have a reserved slot?
if(GetClientCount(false) < MaxClients || Result <= 0)
{
delete pack;
ClientPreConnectEx(sSteam32ID, k_OnClientPreConnectEx_Accept, "");
return;
}
pack.Reset();
AdminId admin = view_as<AdminId>(pack.ReadCell());
int Immunity = pack.ReadCell();
char sName[MAX_NAME_LENGTH];
pack.ReadString(sName, sizeof(sName));
delete pack;
if(Result > Immunity)
Immunity = Result;
if(!KickValidClient(sName, sSteam32ID, admin, Immunity))
ClientPreConnectEx(sSteam32ID, k_OnClientPreConnectEx_Reject, "No reserved slot available, sorry.");
else
ClientPreConnectEx(sSteam32ID, k_OnClientPreConnectEx_Accept, "");
}
stock bool KickValidClient(const char[] sName, const char[] sSteam32ID, AdminId admin, int Immunity)
{
int HighestValue[3] = {-1, ...};
int HighestValueClient[3] = {0, ...};
for(int client = 1; client <= MaxClients; client++)
{
if(!IsClientInGame(client) || IsFakeClient(client))
continue;
bool Donator = view_as<bool>(g_Client_Reservation[client]);
int ConnectionTime = RoundToNearest(GetClientTime(client));
int IdleTime;
if(g_Plugin_AFKManager)
IdleTime = GetClientIdleTime(client);
else // Fall back to highest connection time.
IdleTime = ConnectionTime;
bool HasItem;
#if defined entWatch_core_included
if(g_Plugin_entWatch)
HasItem = EW_ClientHasItem(client);
#endif
/* Spectators
* Sort by idle time and also kick donators if IdleTime > 30
*/
if(GetClientTeam(client) <= CS_TEAM_SPECTATOR)
{
if(!Donator || IdleTime > 30)
{
if(IdleTime > HighestValue[0])
{
HighestValue[0] = IdleTime;
HighestValueClient[0] = client;
}
}
}
/* Spectators */
/* Dead non-donator with IdleTime > 30
* Sort by idle time and don't kick donators.
*/
if(!Donator && GetClientTeam(client) > CS_TEAM_SPECTATOR && !IsPlayerAlive(client))
{
if(IdleTime > 30 && IdleTime > HighestValue[1])
{
HighestValue[1] = IdleTime;
HighestValueClient[1] = client;
}
}
/* Dead non-donator with IdleTime > 30 */
/* Alive non-donator with IdleTime > 30
* Sort by idle time and don't kick donators and item owners.
*/
if(!Donator && IsPlayerAlive(client) && !HasItem)
{
if(IdleTime > 30 && IdleTime > HighestValue[2])
{
HighestValue[2] = IdleTime;
HighestValueClient[2] = client;
}
}
/* Alive non-donator with IdleTime > 30 */
}
// Check if any condition was met in the correct order and perform kick
for(int i = 0; i < sizeof(HighestValue); i++)
{
if(HighestValue[i] != -1)
{
ExecuteKickValidClient(HighestValueClient[i], sName, sSteam32ID, admin, Immunity);
return true;
}
}
return false;
}
stock void ExecuteKickValidClient(int client, const char[] sName, const char[] sSteam32ID, AdminId admin, int Immunity)
{
KickClientEx(client, "Kicked for reserved slot (%s joined).", sName);
}