Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
177 changes: 100 additions & 77 deletions addons/sourcemod/scripting/VIP_SourcemodFlags.sp
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,17 @@

#define VIP_FEATURE_NAME "VIP"

ConVar g_cvVIPGroupName;
ConVar g_cvVIPGroupImmunity;

bool g_bClientLoaded[MAXPLAYERS + 1] = { false, ... };
bool g_bSbppClientsLoaded = false;
bool g_bReloadVips = false;
bool g_bLibraryCCC = false;
bool g_bLateLoaded = false;

// Track original immunity levels and VIP immunity status
int g_iOriginalImmunity[MAXPLAYERS + 1] = { 0, ... };
bool g_bVIPImmunityApplied[MAXPLAYERS + 1] = { false, ... };

public Plugin myinfo =
{
Expand All @@ -30,10 +34,19 @@ public Plugin myinfo =
version = "3.2.3"
};

public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max)
{
g_bLateLoaded = late;
return APLRes_Success;
}

public void OnAllPluginsLoaded()
{
if (LibraryExists("ccc"))
g_bLibraryCCC = true;

if (g_bLateLoaded)
ReloadVIPs();
}

public void OnLibraryAdded(const char[] name)
Expand All @@ -51,8 +64,6 @@ public void OnLibraryRemoved(const char[] name)
public void OnPluginStart()
{
LoadTranslations("common.phrases");

g_cvVIPGroupName = CreateConVar("sm_vip_group_name", "VIP", "Group name of vip users");
g_cvVIPGroupImmunity = CreateConVar("sm_vip_group_immunity", "5", "Immunity level of vip users", 0, true, 0.0, true, 100.0);

RegAdminCmd("sm_reloadvips", Command_ReloadVips, ADMFLAG_BAN);
Expand All @@ -66,7 +77,11 @@ public void OnMapEnd()
g_bSbppClientsLoaded = false;
g_bReloadVips = false;
for (int i = 0; i <= MaxClients; i++)
{
g_bClientLoaded[i] = false;
g_iOriginalImmunity[i] = 0;
g_bVIPImmunityApplied[i] = false;
}
}

public Action Command_ReloadVips(int client, int args)
Expand Down Expand Up @@ -131,29 +146,39 @@ public bool OnClientConnect(int client, char[] rejectmsg, int maxlen)
public void OnClientDisconnect(int client)
{
g_bClientLoaded[client] = false;
g_iOriginalImmunity[client] = 0;
g_bVIPImmunityApplied[client] = false;
}

public Action OnClientPreAdminCheck(int client)
{
return g_bSbppClientsLoaded && g_bClientLoaded[client] ? Plugin_Continue : Plugin_Handled;
// If the client hasn't been processed yet, handle both VIP and non-VIP
if (!g_bClientLoaded[client])
{
if (VIP_IsClientVIP(client))
LoadVIPClient(client);
else
g_bClientLoaded[client] = true; // Non-VIP clients should be marked as processed so they are not blocked

TryNotifyPostAdminCheck(client);
return Plugin_Continue;
}
Copy link

Copilot AI Aug 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LoadVIPClient is called in OnClientPreAdminCheck which can be called multiple times. Consider adding a check to prevent redundant loading operations.

Suggested change
}
if (!g_bClientLoaded[client] && VIP_IsClientVIP(client))
{
g_bClientLoaded[client] = true;
LoadVIPClient(client);
NotifyPostAdminCheck(client);
return Plugin_Handled;
}

Copilot uses AI. Check for mistakes.

return Plugin_Continue;
}

Copy link

Copilot AI Aug 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The OnClientPreAdminCheck function now only handles VIP clients, but non-VIP clients that aren't loaded yet will be blocked indefinitely since g_bClientLoaded[client] remains false for them.

Copilot uses AI. Check for mistakes.
#if defined _sourcebanspp_included
public bool SBPP_OnClientPreAdminCheck(AdminCachePart part)
{
if (part == AdminCache_Admins)
{
g_bSbppClientsLoaded = true;

for (int client = 1; client <= MaxClients; client++)
CheckLoadAdmin(client);

if (part == AdminCache_Admins)
{
if (g_bReloadVips)
ReloadVIPs();

g_bReloadVips = false;
}
Comment on lines 177 to 181
Copy link

Copilot AI Sep 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The g_bReloadVips flag is reset regardless of whether ReloadVIPs() was called. This could cause issues if the flag was set for a different AdminCachePart type. The flag should only be reset when the reload actually occurs.

Suggested change
if (g_bReloadVips)
ReloadVIPs();
g_bReloadVips = false;
}
if (g_bReloadVips)
{
ReloadVIPs();
g_bReloadVips = false;
}
}

Copilot uses AI. Check for mistakes.

return false;
}
#endif
Expand All @@ -179,27 +204,19 @@ public void VIP_OnVIPClientRemoved(int client, const char[] szReason, int iAdmin
}

stock void UnloadVIPClient(int client)
{
RemoveClient(client);

#if defined _ccc_included
if (g_bLibraryCCC && GetFeatureStatus(FeatureType_Native, "CCC_UnLoadClient") == FeatureStatus_Available)
CCC_UnLoadClient(client);
#endif

ServerCommand("sm_reloadadmins");
}

stock void LoadVIPClient(int client)
{
if (!client)
return;

LoadClient(client);
RemoveClient(client);

// Reset client loaded flag to allow reprocessing if VIP status is regained
g_bClientLoaded[client] = false;
g_bVIPImmunityApplied[client] = false;

#if defined _ccc_included
if (g_bLibraryCCC && GetFeatureStatus(FeatureType_Native, "CCC_LoadClient") == FeatureStatus_Available)
CCC_LoadClient(client);
if (g_bLibraryCCC && GetFeatureStatus(FeatureType_Native, "CCC_UnLoadClient") == FeatureStatus_Available)
CCC_UnLoadClient(client);
#endif
}

Expand All @@ -210,88 +227,94 @@ stock void RemoveClient(int client)
GetClientAuthId(client, AuthId_Steam2, sAuth, sizeof(sAuth));

AdminId curAdm = INVALID_ADMIN_ID;
// find and delete the admin using that identity
if ((curAdm = FindAdminByIdentity(sAuthType, sAuth)) != INVALID_ADMIN_ID)
{
RemoveAdmin(curAdm);
}
// Remove VIP flags
SetAdminFlag(curAdm, Admin_Custom1, false);
SetAdminFlag(curAdm, Admin_Custom2, false);

g_bClientLoaded[client] = true;
// Only restore immunity if VIP immunity was actually applied
if (g_bVIPImmunityApplied[client])
{
// Restore original immunity level
SetAdminImmunityLevel(curAdm, g_iOriginalImmunity[client]);
}
}

CheckLoadAdmin(client);
TryNotifyPostAdminCheck(client);
Copy link

Copilot AI Sep 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Calling TryNotifyPostAdminCheck which has an incomplete implementation. This will cause runtime issues as the function body is missing.

Copilot uses AI. Check for mistakes.
Copy link

Copilot AI Sep 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function name TryNotifyPostAdminCheck is inconsistent with the usage of NotifyPostAdminCheck on line 163. These should use the same function name for consistency.

Copilot uses AI. Check for mistakes.
}

Copy link

Copilot AI Aug 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Setting g_bClientLoaded[client] to false in RemoveClient function contradicts the function's purpose. This should remain true to indicate the client has been processed, or the logic needs to be reconsidered.

Copilot uses AI. Check for mistakes.
stock void LoadClient(int client)
stock void LoadVIPClient(int client)
{
ArrayList Groups = new ArrayList(ByteCountToCells(32));
char sVIPGroupName[64];
if (!client)
return;

if (VIP_IsClientVIP(client))
{
if (!VIP_GetClientVIPGroup(client, sVIPGroupName, sizeof(sVIPGroupName)))
g_cvVIPGroupName.GetString(sVIPGroupName, sizeof(sVIPGroupName));
char sAuthType[] = "steam";
char sAuth[32];
GetClientAuthId(client, AuthId_Steam2, sAuth, sizeof(sAuth));

Groups.PushString(sVIPGroupName);
AdminId curAdm = INVALID_ADMIN_ID;
if ((curAdm = FindAdminByIdentity(sAuthType, sAuth)) == INVALID_ADMIN_ID)
{
char sName[254];
GetClientName(client, sName, sizeof(sName));
curAdm = CreateAdmin(sName);
if (!curAdm.BindIdentity(sAuthType, sAuth))
{
RemoveAdmin(curAdm);
return;
}
}

if (Groups.Length)
if (VIP_IsClientVIP(client))
{
char sAuthType[] = "steam";
char sAuth[32];
GetClientAuthId(client, AuthId_Steam2, sAuth, sizeof(sAuth));
// Add VIP flags to existing admin
SetAdminFlag(curAdm, Admin_Custom1, true);
SetAdminFlag(curAdm, Admin_Custom2, true);

// Check current immunity level
int currentImmunity = GetAdminImmunityLevel(curAdm);
int vipImmunity = g_cvVIPGroupImmunity.IntValue;

// Store original immunity level only if VIP immunity was not previously applied
if (!g_bVIPImmunityApplied[client])
g_iOriginalImmunity[client] = currentImmunity;

AdminId curAdm = INVALID_ADMIN_ID;
// find or create the admin using that identity
if ((curAdm = FindAdminByIdentity(sAuthType, sAuth)) == INVALID_ADMIN_ID)
// Only set VIP immunity if it's higher than current immunity
if (vipImmunity > currentImmunity)
{
char sName[254];
GetClientName(client, sName, sizeof(sName));
curAdm = CreateAdmin(sName);
// That should never happen!
if (!curAdm.BindIdentity(sAuthType, sAuth))
{
RemoveAdmin(curAdm);
delete Groups;
return;
}
SetAdminImmunityLevel(curAdm, vipImmunity);
g_bVIPImmunityApplied[client] = true;
}

for (int i = 0; i < Groups.Length; i++)
else
{
char sGroup[32];
Groups.GetString(i, sGroup, sizeof(sGroup));

GroupId grp;
if((grp = FindAdmGroup(sGroup)) == INVALID_GROUP_ID)
{
grp = CreateAdmGroup(sGroup);
if (StrEqual(sGroup, sVIPGroupName))
{
SetAdmGroupAddFlag(grp, Admin_Custom1, true);
SetAdmGroupAddFlag(grp, Admin_Custom2, true);
SetAdmGroupImmunityLevel(grp, g_cvVIPGroupImmunity.IntValue);
}
}

AdminInheritGroup(curAdm, grp);
// VIP immunity not applied because current immunity is higher
g_bVIPImmunityApplied[client] = false;
}
}

delete Groups;

g_bClientLoaded[client] = true;
TryNotifyPostAdminCheck(client);
Copy link

Copilot AI Sep 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Calling TryNotifyPostAdminCheck which has an incomplete implementation. This will cause runtime issues as the function body is missing.

Copilot uses AI. Check for mistakes.

CheckLoadAdmin(client);
#if defined _ccc_included
if (g_bLibraryCCC && GetFeatureStatus(FeatureType_Native, "CCC_LoadClient") == FeatureStatus_Available)
CCC_LoadClient(client);
#endif
}

stock void CheckLoadAdmin(int client)
// Apply admin cache and conditionally notify post-admin check if client is ready and SBPP is loaded
stock void TryNotifyPostAdminCheck(int client)
{
if (IsClientInGame(client) && IsClientAuthorized(client))
{
RunAdminCacheChecks(client);

#if defined _sourcebanspp_included
if (g_bSbppClientsLoaded && g_bClientLoaded[client])
{
NotifyPostAdminCheck(client);
}
#endif
}
}

Expand Down