580 lines
19 KiB
SourcePawn
580 lines
19 KiB
SourcePawn
#pragma semicolon 1
|
|
|
|
#include <sourcemod>
|
|
#include <basecomm>
|
|
#include <connect>
|
|
#include <geoip>
|
|
|
|
#pragma newdecls required
|
|
|
|
/* CONVARS */
|
|
ConVar g_hCvar_BlockSpoof;
|
|
ConVar g_hCvar_BlockAdmin;
|
|
ConVar g_hCvar_BlockVoice;
|
|
ConVar g_hCvar_AuthenticationTime;
|
|
|
|
/* DATABASE */
|
|
Database g_hDatabase;
|
|
|
|
/* STRING */
|
|
char g_cPlayerGUID[MAXPLAYERS + 1][40];
|
|
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------------------------------
|
|
public Plugin myinfo =
|
|
{
|
|
name = "PlayerManager: Connect",
|
|
author = "zaCade + Neon",
|
|
description = "Manage clients, denying admin access, ect.",
|
|
version = "2.1.0"
|
|
};
|
|
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------------------------------
|
|
public APLRes AskPluginLoad2(Handle hMyself, bool bLate, char[] sError, int errorSize)
|
|
{
|
|
CreateNative("PM_IsPlayerSteam", Native_IsPlayerSteam);
|
|
CreateNative("PM_GetPlayerType", Native_GetPlayerType);
|
|
CreateNative("PM_GetPlayerGUID", Native_GetPlayerGUID);
|
|
|
|
RegPluginLibrary("PlayerManager");
|
|
return APLRes_Success;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------------------------------
|
|
public void OnPluginStart()
|
|
{
|
|
LoadTranslations("common.phrases");
|
|
|
|
g_hCvar_BlockSpoof = CreateConVar("sm_manager_block_spoof", "1", "Kick unauthenticated people that join with known steamids.", FCVAR_NONE, true, 0.0, true, 1.0);
|
|
g_hCvar_BlockAdmin = CreateConVar("sm_manager_block_admin", "1", "Should unauthenticated people be blocked from admin?", FCVAR_NONE, true, 0.0, true, 1.0);
|
|
g_hCvar_BlockVoice = CreateConVar("sm_manager_block_voice", "1", "Should unauthenticated people be blocked from voice?", FCVAR_NONE, true, 0.0, true, 1.0);
|
|
g_hCvar_AuthenticationTime = CreateConVar("sm_manager_authentication_time", "15", "Time in seconds after which a client needs to be assigned to a SteamID", FCVAR_NONE, true, 1.0);
|
|
|
|
AddMultiTargetFilter("@steam", Filter_Steam, "Steam Players", false);
|
|
AddMultiTargetFilter("@nosteam", Filter_NoSteam, "No-Steam Players", false);
|
|
|
|
RegConsoleCmd("sm_steam", Command_DisplaySteamStats, "Shows No-Steam players");
|
|
RegConsoleCmd("sm_nosteam", Command_DisplaySteamStats, "Shows No-Steam players");
|
|
RegAdminCmd("sm_auth", Command_GetAuth, ADMFLAG_GENERIC, "Retreives the Steam ID of a player");
|
|
RegAdminCmd("sm_debugnosteam", Command_DebugNoSteam, ADMFLAG_GENERIC, "Retreives the amount of No-Steam players");
|
|
|
|
AutoExecConfig();
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------------------------------
|
|
public void OnConfigsExecuted()
|
|
{
|
|
if(!g_hCvar_BlockSpoof.BoolValue)
|
|
return;
|
|
if (!g_hDatabase)
|
|
{
|
|
Database.Connect(SQL_OnDatabaseConnect, "PlayerManager");
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------------------------------
|
|
public void OnPluginEnd()
|
|
{
|
|
RemoveMultiTargetFilter("@steam", Filter_Steam);
|
|
RemoveMultiTargetFilter("@nosteam", Filter_NoSteam);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------------------------------
|
|
public bool SteamClientAuthenticatedEx(const char[] sAuthID)
|
|
{
|
|
//neons steam ID. he got a vac ban, this lets him avoid it. told him he should get a new account but he never got a new one.
|
|
if (StrEqual(sAuthID, "STEAM_0:1:32247009"))
|
|
return true;
|
|
|
|
return SteamClientAuthenticated(sAuthID);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------------------------------
|
|
public Action Command_GetAuth(int client, int args)
|
|
{
|
|
if(args < 1)
|
|
{
|
|
ReplyToCommand(client, "[SM] Usage: sm_auth <#userid|name>");
|
|
return Plugin_Handled;
|
|
}
|
|
|
|
char sTarget[MAX_TARGET_LENGTH];
|
|
GetCmdArg(1, sTarget, sizeof(sTarget));
|
|
|
|
int iTarget;
|
|
if ((iTarget = FindTarget(client, sTarget, false, false)) <= 0)
|
|
return Plugin_Handled;
|
|
|
|
char sAuthID[32];
|
|
GetClientAuthId(iTarget, AuthId_Steam2, sAuthID, sizeof(sAuthID));
|
|
|
|
ReplyToCommand(client, "[SM] The Steam ID of %N is:", iTarget);
|
|
ReplyToCommand(client, "%s", sAuthID);
|
|
|
|
return Plugin_Handled;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------------------------------
|
|
public Action Command_DisplaySteamStats(int client, int args)
|
|
{
|
|
char aBuf[1024];
|
|
char aBuf2[MAX_NAME_LENGTH];
|
|
|
|
for(int i = 1; i <= MaxClients; i++)
|
|
{
|
|
if(IsClientInGame(i) && !IsFakeClient(i))
|
|
{
|
|
char sAuthID[32];
|
|
GetClientAuthId(i, AuthId_Steam2, sAuthID, sizeof(sAuthID), false);
|
|
|
|
if(!SteamClientAuthenticatedEx(sAuthID))
|
|
{
|
|
GetClientName(i, aBuf2, sizeof(aBuf2));
|
|
StrCat(aBuf, sizeof(aBuf), aBuf2);
|
|
StrCat(aBuf, sizeof(aBuf), ", ");
|
|
}
|
|
}
|
|
}
|
|
|
|
if(strlen(aBuf))
|
|
{
|
|
aBuf[strlen(aBuf) - 2] = 0;
|
|
ReplyToCommand(client, "[SM] No-Steam clients online: %s", aBuf);
|
|
}
|
|
else
|
|
ReplyToCommand(client, "[SM] No-Steam clients online: none");
|
|
|
|
return Plugin_Handled;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------------------------------
|
|
public Action Command_DebugNoSteam(int client, int args)
|
|
{
|
|
int iNoSteamAmount;
|
|
|
|
for(int i = 1; i <= MaxClients; i++)
|
|
{
|
|
if(IsClientInGame(i) && !IsFakeClient(i))
|
|
{
|
|
char sAuthID[32];
|
|
GetClientAuthId(i, AuthId_Steam2, sAuthID, sizeof(sAuthID), false);
|
|
|
|
if(!SteamClientAuthenticated(sAuthID))
|
|
iNoSteamAmount++;
|
|
}
|
|
}
|
|
|
|
ReplyToCommand(client, "[SM] There are currently %d No-Steam Clients online.", iNoSteamAmount);
|
|
|
|
return Plugin_Handled;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------------------------------
|
|
public bool Filter_Steam(const char[] sPattern, Handle hClients)
|
|
{
|
|
for(int i = 1; i <= MaxClients; i++)
|
|
{
|
|
if(IsClientInGame(i) && !IsFakeClient(i))
|
|
{
|
|
char sAuthID[32];
|
|
GetClientAuthId(i, AuthId_Steam2, sAuthID, sizeof(sAuthID), false);
|
|
|
|
if(SteamClientAuthenticatedEx(sAuthID))
|
|
PushArrayCell(hClients, i);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------------------------------
|
|
public bool Filter_NoSteam(const char[] sPattern, Handle hClients)
|
|
{
|
|
for(int i = 1; i <= MaxClients; i++)
|
|
{
|
|
if(IsClientInGame(i) && !IsFakeClient(i))
|
|
{
|
|
char sAuthID[32];
|
|
GetClientAuthId(i, AuthId_Steam2, sAuthID, sizeof(sAuthID), false);
|
|
|
|
if(!SteamClientAuthenticatedEx(sAuthID))
|
|
PushArrayCell(hClients, i);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------------------------------
|
|
public EConnect OnClientPreConnectEx(const char[] sName, char sPassword[255], const char[] sIP, const char[] sSteam32ID, char sRejectReason[255])
|
|
{
|
|
char sAuthID[32];
|
|
for(int client = 1; client <= MaxClients; client++)
|
|
{
|
|
if(IsClientInGame(client) && !IsFakeClient(client))
|
|
{
|
|
GetClientAuthId(client, AuthId_Steam2, sAuthID, sizeof(sAuthID), false);
|
|
|
|
if(StrEqual(sAuthID, sSteam32ID, false))
|
|
{
|
|
char sClientIP[32];
|
|
GetClientIP(client, sClientIP, sizeof(sClientIP));
|
|
if(IsClientTimingOut(client) || StrEqual(sIP, sClientIP, false))
|
|
{
|
|
KickClientEx(client, "Timed out");
|
|
return k_OnClientPreConnectEx_Accept;
|
|
}
|
|
else
|
|
{
|
|
LogAction(client, -1, "\"%L\" got protected from getting kicked by a new connection. Possible spoofing attempt from IP: %s", client, sIP);
|
|
Format(sRejectReason, sizeof(sRejectReason), "SteamID already on the server");
|
|
return k_OnClientPreConnectEx_Reject;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return k_OnClientPreConnectEx_Accept;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------------------------------
|
|
public void OnClientPutInServer(int client)
|
|
{
|
|
//CreateTimer(g_hCvar_AuthenticationTime.FloatValue, CheckAuth, GetClientSerial(client), TIMER_FLAG_NO_MAPCHANGE);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------------------------------
|
|
public void OnClientAuthorized(int client, const char[] sAuthID)
|
|
{
|
|
char sAddress[16];
|
|
GetClientIP(client, sAddress, sizeof(sAddress));
|
|
static char sCountry[32];
|
|
//just kicking all nosteamers from algeria. not very cool but so be it.
|
|
if (GeoipCountry(sAddress, sCountry, sizeof(sCountry)) && StrEqual(sCountry, "Algeria", false))
|
|
{
|
|
if (!SteamClientAuthenticatedEx(sAuthID))
|
|
{
|
|
LogMessage("kicking client for being algerian nosteamer: name: %N. sAuthID: %s", client, sAuthID);
|
|
KickClient(client, "Bye. if you dont think this was deserved please contact us on discord.");
|
|
return;
|
|
}
|
|
}
|
|
if(!g_hCvar_BlockSpoof.BoolValue || !g_hDatabase)
|
|
return;
|
|
|
|
if(IsFakeClient(client) || IsClientSourceTV(client))
|
|
return;
|
|
|
|
char sQuery[512];
|
|
Format(sQuery, sizeof(sQuery), "SELECT * FROM connections WHERE auth='%s'", sAuthID);
|
|
|
|
g_hDatabase.Query(SQL_OnQueryCompleted, sQuery, GetClientSerial(client), DBPrio_Low);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------------------------------
|
|
public Action OnClientPreAdminCheck(int client)
|
|
{
|
|
if(!g_hCvar_BlockAdmin.BoolValue)
|
|
return Plugin_Continue;
|
|
|
|
if(IsFakeClient(client) || IsClientSourceTV(client))
|
|
return Plugin_Continue;
|
|
|
|
char sAuthID[32];
|
|
GetClientAuthId(client, AuthId_Steam2, sAuthID, sizeof(sAuthID), false);
|
|
|
|
if(!SteamClientAuthenticatedEx(sAuthID))
|
|
{
|
|
LogMessage("%L was not authenticated with steam, denying admin.", client);
|
|
NotifyPostAdminCheck(client);
|
|
return Plugin_Handled;
|
|
}
|
|
else return Plugin_Continue;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------------------------------
|
|
public void OnClientPostAdminCheck(int client)
|
|
{
|
|
if(!g_hCvar_BlockVoice.BoolValue)
|
|
return;
|
|
|
|
if(IsFakeClient(client) || IsClientSourceTV(client))
|
|
return;
|
|
|
|
char sAuthID[32];
|
|
GetClientAuthId(client, AuthId_Steam2, sAuthID, sizeof(sAuthID), false);
|
|
|
|
/*
|
|
if(!SteamClientAuthenticatedEx(sAuthID))
|
|
{
|
|
LogMessage("%L was not authenticated with steam, muting client.", client);
|
|
BaseComm_SetClientMute(client, true);
|
|
return;
|
|
}
|
|
*/
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------------------------------
|
|
public Action CheckAuth(Handle timer, int data)
|
|
{
|
|
int client;
|
|
if ((client = GetClientFromSerial(data)) == 0)
|
|
return Plugin_Stop;
|
|
|
|
char sAuthID[32];
|
|
if(!GetClientAuthId(client, AuthId_Steam2, sAuthID, sizeof(sAuthID), true))
|
|
{
|
|
LogMessage("%L could not be assigned to a SteamID, kicking client.", client);
|
|
//KickClient(client, "Invalid STEAMID");
|
|
if (IsValidClient(client))
|
|
{
|
|
Panel hNotifyPanel = new Panel(GetMenuStyleHandle(MenuStyle_Radio));
|
|
hNotifyPanel.DrawItem("WARNING: Your SteamID is Invalid: Reconnecting you to the server in 8 Seconds.", ITEMDRAW_RAWLINE);
|
|
hNotifyPanel.DrawItem("", ITEMDRAW_SPACER);
|
|
hNotifyPanel.DrawItem("IMPORTANT: You may disconnect, reconnect if necessary!", ITEMDRAW_RAWLINE);
|
|
hNotifyPanel.Send(client, MenuHandler_NotifyPanel, 8);
|
|
delete hNotifyPanel;
|
|
|
|
for (int i = 0; i < 8; i++)
|
|
{
|
|
PrintToChat(client, "WARNING: Your SteamID is Invalid: Reconnecting you to the server in 8 Seconds.");
|
|
}
|
|
|
|
CreateTimer(8.0, forceClientRetry, GetClientSerial(client));
|
|
}
|
|
}
|
|
return Plugin_Stop;
|
|
}
|
|
|
|
public Action forceClientRetry(Handle timer, int data)
|
|
{
|
|
int client;
|
|
if ((client = GetClientFromSerial(data)) == 0)
|
|
return Plugin_Stop;
|
|
if (IsValidClient(client))
|
|
{
|
|
ClientCommand(client, "retry");
|
|
}
|
|
return Plugin_Handled;
|
|
}
|
|
|
|
stock bool IsValidClient(int client)
|
|
{
|
|
if (client > 0 && client <= MaxClients && IsClientConnected(client) && IsClientInGame(client) && !IsClientSourceTV(client) && !IsFakeClient(client))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
int MenuHandler_NotifyPanel(Menu hMenu, MenuAction iAction, int iParam1, int iParam2)
|
|
{
|
|
switch (iAction)
|
|
{
|
|
case MenuAction_Select, MenuAction_Cancel:
|
|
delete hMenu;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------------------------------
|
|
public void SQL_OnDatabaseConnect(Database db, const char[] error, any data)
|
|
{
|
|
if(!db || strlen(error))
|
|
{
|
|
LogError("Database error: %s", error);
|
|
return;
|
|
}
|
|
|
|
g_hDatabase = db;
|
|
|
|
char sQuery[512];
|
|
Format(sQuery, sizeof(sQuery), "CREATE TABLE IF NOT EXISTS connections (`auth` varchar(32), `type` varchar(32), `address` varchar(16), PRIMARY KEY (`auth`))");
|
|
|
|
g_hDatabase.Query(SQL_OnQueryCompleted, sQuery, _, DBPrio_High);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------------------------------
|
|
public void SQL_OnQueryCompleted(Database db, DBResultSet results, const char[] error, any data)
|
|
{
|
|
if(!db || strlen(error))
|
|
{
|
|
LogError("Query error: %s", error);
|
|
return;
|
|
}
|
|
|
|
int client;
|
|
if ((client = GetClientFromSerial(data)) == 0)
|
|
return;
|
|
|
|
char sAuthID[32];
|
|
GetClientAuthId(client, AuthId_Steam2, sAuthID, sizeof(sAuthID), false);
|
|
|
|
char sAddress[16];
|
|
GetClientIP(client, sAddress, sizeof(sAddress));
|
|
|
|
char sConnectionType[32];
|
|
if(SteamClientAuthenticatedEx(sAuthID))
|
|
sConnectionType = "SteamLegit";
|
|
else
|
|
sConnectionType = "NoAuth";
|
|
|
|
if(results.RowCount && results.FetchRow())
|
|
{
|
|
int iFieldNum;
|
|
char sResultAddress[16];
|
|
char sResultConnectionType[32];
|
|
|
|
results.FieldNameToNum("address", iFieldNum);
|
|
results.FetchString(iFieldNum, sResultAddress, sizeof(sResultAddress));
|
|
|
|
results.FieldNameToNum("type", iFieldNum);
|
|
results.FetchString(iFieldNum, sResultConnectionType, sizeof(sResultConnectionType));
|
|
|
|
delete results;
|
|
|
|
if(!SteamClientAuthenticatedEx(sAuthID))
|
|
{
|
|
if(!StrEqual(sConnectionType, sResultConnectionType, false) && StrEqual(sResultConnectionType, "SteamLegit", false))
|
|
{
|
|
if(StrEqual(sAddress, sResultAddress, false))
|
|
{
|
|
LogMessage("%L tried to join with a legitimate steamid while not authenticated with steam. Allowing connection, IPs match. (Known: %s)", client, sAddress);
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
LogAction(client, -1, "\"%L\" tried to join with a legitimate steamid while not authenticated with steam. Refusing connection, IPs dont match. (Known: %s | Current: %s)", client, sResultAddress, sAddress);
|
|
static char sCountry[32];
|
|
//we were directly got a problem with an algerian. this is just a specific issue with a specific solution.
|
|
if (GeoipCountry(sAddress, sCountry, sizeof(sCountry)) && StrEqual(sCountry, "Algeria", false))
|
|
{
|
|
KickClient(client, "Trying to join with a legitimate steamid while not authenticated with steam.");
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
char sQuery[512];
|
|
Format(sQuery, sizeof(sQuery), "INSERT INTO connections (auth, type, address) VALUES ('%s', '%s', '%s') ON DUPLICATE KEY UPDATE type='%s', address='%s';", sAuthID, sConnectionType, sAddress, sConnectionType, sAddress);
|
|
|
|
g_hDatabase.Query(SQL_OnQueryCompleted, sQuery, _, DBPrio_Low);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------------------------------
|
|
public int Native_IsPlayerSteam(Handle hPlugin, int numParams)
|
|
{
|
|
int client = GetNativeCell(1);
|
|
|
|
if (client < 1 || client > MaxClients)
|
|
{
|
|
return ThrowNativeError(SP_ERROR_NATIVE, "Client index %d is invalid", client);
|
|
}
|
|
else if (!IsClientConnected(client))
|
|
{
|
|
return ThrowNativeError(SP_ERROR_NATIVE, "Client %d is not connected", client);
|
|
}
|
|
else if (IsFakeClient(client))
|
|
{
|
|
return ThrowNativeError(SP_ERROR_NATIVE, "Client %d is a bot", client);
|
|
}
|
|
|
|
char sAuthID[32];
|
|
GetClientAuthId(client, AuthId_Steam2, sAuthID, sizeof(sAuthID), false);
|
|
|
|
if(SteamClientAuthenticatedEx(sAuthID))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------------------------------
|
|
public int Native_GetPlayerType(Handle hPlugin, int numParams)
|
|
{
|
|
int client = GetNativeCell(1);
|
|
int length = GetNativeCell(3);
|
|
|
|
if (client < 1 || client > MaxClients)
|
|
{
|
|
return ThrowNativeError(SP_ERROR_NATIVE, "Client index %d is invalid", client);
|
|
}
|
|
else if (!IsClientConnected(client))
|
|
{
|
|
return ThrowNativeError(SP_ERROR_NATIVE, "Client %d is not connected", client);
|
|
}
|
|
else if (IsFakeClient(client))
|
|
{
|
|
return ThrowNativeError(SP_ERROR_NATIVE, "Client %d is a bot", client);
|
|
}
|
|
|
|
char sAuthID[32];
|
|
GetClientAuthId(client, AuthId_Steam2, sAuthID, sizeof(sAuthID), false);
|
|
|
|
if(SteamClientAuthenticatedEx(sAuthID))
|
|
return !SetNativeString(2, "SteamLegit", length + 1);
|
|
|
|
return !SetNativeString(2, "NoAuth", length + 1);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------------------------------
|
|
public int Native_GetPlayerGUID(Handle hPlugin, int numParams)
|
|
{
|
|
int client = GetNativeCell(1);
|
|
int length = GetNativeCell(3);
|
|
|
|
if (client < 1 || client > MaxClients)
|
|
{
|
|
return ThrowNativeError(SP_ERROR_NATIVE, "Client index %d is invalid", client);
|
|
}
|
|
else if (!IsClientConnected(client))
|
|
{
|
|
return ThrowNativeError(SP_ERROR_NATIVE, "Client %d is not connected", client);
|
|
}
|
|
else if (IsFakeClient(client))
|
|
{
|
|
return ThrowNativeError(SP_ERROR_NATIVE, "Client %d is a bot", client);
|
|
}
|
|
|
|
return !SetNativeString(2, g_cPlayerGUID[client], length + 1);
|
|
}
|