diff --git a/core/smn_player.cpp b/core/smn_player.cpp index 95490bc1..6a052f13 100644 --- a/core/smn_player.cpp +++ b/core/smn_player.cpp @@ -37,6 +37,15 @@ #include #include +#ifndef PRIu64 +#ifdef _WIN32 +#define PRIu64 "I64u" +#else +#define PRIu64 "llu" +#endif +#endif + + static cell_t sm_GetMaxHumanPlayers(IPluginContext *pCtx, const cell_t *params) { int maxHumans = -1; @@ -380,6 +389,111 @@ static cell_t RunAdminCacheChecks(IPluginContext *pContext, const cell_t *params return (id != pPlayer->GetAdminId()) ? 1 : 0; } +// Must match clients.inc +enum AuthIdType +{ + AuthType_Engine = 0, + AuthType_Steam2, + AuthType_Steam3, + AuthType_SteamId64, +}; + +static cell_t GetClientAuthId(IPluginContext *pContext, const cell_t *params) +{ + CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]); + if (!pPlayer) + { + return pContext->ThrowNativeError("Client index %d is invalid", params[1]); + } + else if (!pPlayer->IsConnected()) + { + return pContext->ThrowNativeError("Client %d is not connected", params[1]); + } + + switch (params[2]) + { + case AuthType_Engine: + { + const char *authstr = pPlayer->GetAuthString(params[5]); + if (!authstr || authstr[0] == '\0') + { + return 0; + } + pContext->StringToLocal(params[3], params[4], authstr); + } + break; + case AuthType_Steam2: + case AuthType_Steam3: + { + if (pPlayer->IsFakeClient()) + { + pContext->StringToLocal(params[3], params[4], "BOT"); + return 1; + } + + static char authstr[64]; + unsigned int acctId = pPlayer->GetSteamAccountID(params[5]); + if (acctId == 0) + { + if (g_HL2.IsLANServer()) + { + pContext->StringToLocal(params[3], params[4], "STEAM_ID_LAN"); + return 1; + } + else if (!params[5]) + { + pContext->StringToLocal(params[3], params[4], "STEAM_ID_PENDING"); + return 1; + } + + return 0; + } + + if (params[2] == AuthType_Steam2) + { +#if SOURCE_ENGINE <= SE_LEFT4DEAD + unsigned int universe = 0; +#else + unsigned int universe = 1; +#endif + _snprintf(authstr, sizeof(authstr), "STEAM_%u:%u:%u", universe, acctId & 1, acctId >> 1); + pContext->StringToLocal(params[3], params[4], authstr); + break; + } + else + { + _snprintf(authstr, sizeof(authstr), "[U:1:%u]", acctId); + pContext->StringToLocal(params[3], params[4], authstr); + } + } + break; + case AuthType_SteamId64: + { + if (pPlayer->IsFakeClient() || g_HL2.IsLANServer()) + { + return 0; + } + unsigned int acctId = pPlayer->GetSteamAccountID(params[5]); + if (acctId == 0) + { + return 0; + } + + uint64_t steamId = acctId; + steamId |= ((uint64_t)1<<32); // Instance (1/Desktop) + steamId |= ((uint64_t)1<<52); // Type (1/Individual) + steamId |= ((uint64_t)1<<56); // Universe (1/Public) + + static char authstr[64]; + snprintf(authstr, sizeof(authstr), "%" PRIu64, steamId); + pContext->StringToLocal(params[3], params[4], authstr); + } + break; + } + + return 1; +} + REGISTER_NATIVES(playernatives) { {"GetMaxHumanPlayers", sm_GetMaxHumanPlayers}, @@ -393,6 +507,7 @@ REGISTER_NATIVES(playernatives) {"GetClientAvgData", GetAvgData}, {"GetClientAvgPackets", GetAvgPackets}, {"RunAdminCacheChecks", RunAdminCacheChecks}, + {"GetClientAuthId", GetClientAuthId}, {NULL, NULL} }; diff --git a/plugins/include/clients.inc b/plugins/include/clients.inc index 3627e971..dc532fed 100644 --- a/plugins/include/clients.inc +++ b/plugins/include/clients.inc @@ -45,6 +45,25 @@ enum NetFlow NetFlow_Both, /**< Both values added together */ }; +/** + * Auth string types. + * + * Note that for the Steam2 and Steam3 types, the following ids are + * also valid values: + * "STEAM_ID_PENDING" - Authentication is pending. + * "STEAM_ID_LAN" - Authentication is disabled because of being on a LAN server. + * "BOT" - The client is a bot. + */ +enum AuthIdType +{ + AuthId_Engine = 0, /**< The game-specific auth string as returned from the engine */ + + // The following are only available on games that support Steam authentication. + AuthId_Steam2, /**< Steam2 rendered format, ex "STEAM_1:1:4153990" */ + AuthId_Steam3, /**< Steam3 rendered format, ex "[U:1:8307981]" */ + AuthId_SteamID64, /**< A SteamID64 (uint64) as a String, ex "76561197968573709" */ +}; + /** * MAXPLAYERS is not the same as MaxClients. * MAXPLAYERS is a hardcoded value as an upper limit. MaxClients changes based on the server. @@ -261,14 +280,29 @@ native bool:GetClientIP(client, String:ip[], maxlen, bool:remport=true); * @param client Player index. * @param auth Buffer to store the client's auth string. * @param maxlen Maximum length of string buffer (includes NULL terminator). - * @param validate Check backend validation status. - * DO NOT PASS FALSE UNLESS YOU UNDERSTAND THE CONSEQUENCES, + * @param validate Check backend validation status. + * DO NOT PASS FALSE UNLESS YOU UNDERSTAND THE CONSEQUENCES, * You WILL KNOW if you need to use this, MOST WILL NOT. * @return True on success, false otherwise. * @error If the client is not connected or the index is invalid. */ native bool:GetClientAuthString(client, String:auth[], maxlen, bool:validate=true); +/** + * Retrieves a client's authentication string (SteamID). + * + * @param client Player index. + * @param authType Auth id type and format to use. + * @param auth Buffer to store the client's auth id. + * @param maxlen Maximum length of string buffer (includes NULL terminator). + * @param validate Check backend validation status. + * DO NOT PASS FALSE UNLESS YOU UNDERSTAND THE CONSEQUENCES, + * You WILL KNOW if you need to use this, MOST WILL NOT. + * @return True on success, false otherwise. + * @error If the client is not connected or the index is invalid. + */ +native bool:GetClientAuthId(client, AuthIdType:authType, String:auth[], maxlen, bool:validate=true); + /** * Returns the client's Steam account ID. *