diff --git a/AMBuildScript b/AMBuildScript index 6ada6eb9bf..863d7c2860 100644 --- a/AMBuildScript +++ b/AMBuildScript @@ -819,7 +819,7 @@ else: 'core/AMBuilder', 'core/logic/AMBuilder', 'extensions/bintools/AMBuilder', - 'extensions/clientprefs/AMBuilder', + #'extensions/clientprefs/AMBuilder', 'extensions/curl/AMBuilder', 'extensions/cstrike/AMBuilder', 'extensions/dhooks/AMBuilder', diff --git a/extensions/clientprefs/AMBuilder b/extensions/clientprefs/AMBuilder deleted file mode 100644 index ba61ea4acf..0000000000 --- a/extensions/clientprefs/AMBuilder +++ /dev/null @@ -1,24 +0,0 @@ -# vim: set sts=2 ts=8 sw=2 tw=99 et ft=python: -import os - -for cxx in builder.targets: - binary = SM.ExtLibrary(builder, cxx, 'clientprefs.ext') - binary.compiler.cxxincludes += [ - os.path.join(SM.mms_root, 'core', 'sourcehook'), - ] - if binary.compiler.family == 'gcc' or binary.compiler.family == 'clang': - binary.compiler.cxxflags += ['-fno-rtti'] - elif binary.compiler.family == 'msvc': - binary.compiler.cxxflags += ['/GR-'] - - binary.sources += [ - 'extension.cpp', - 'cookie.cpp', - 'menus.cpp', - 'natives.cpp', - 'query.cpp', - '../../public/smsdk_ext.cpp' - ] - - SM.extensions += [builder.Add(binary)] - diff --git a/extensions/clientprefs/cookie.cpp b/extensions/clientprefs/cookie.cpp deleted file mode 100644 index 6c04fef52d..0000000000 --- a/extensions/clientprefs/cookie.cpp +++ /dev/null @@ -1,381 +0,0 @@ -/** - * vim: set ts=4 sw=4 tw=99 noet: - * ============================================================================= - * SourceMod Client Preferences Extension - * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#include "cookie.h" -#include "menus.h" -#include "query.h" - -CookieManager g_CookieManager; - -CookieManager::CookieManager() -{ - for (int i=0; i<=SM_MAXPLAYERS; i++) - { - connected[i] = false; - statsLoaded[i] = false; - statsPending[i] = false; - } - - cookieDataLoadedForward = NULL; - clientMenu = NULL; -} -CookieManager::~CookieManager(){} - -void CookieManager::Unload() -{ - /* If clients are connected we should try save their data */ - for (int i = playerhelpers->GetMaxClients()+1; --i > 0;) - { - if (connected[i]) - OnClientDisconnecting(i); - } - - /* Find all cookies and delete them */ - for (size_t iter = 0; iter < cookieList.size(); ++iter) - delete cookieList[iter]; - - cookieList.clear(); -} - -Cookie *CookieManager::FindCookie(const char *name) -{ - Cookie *cookie; - if (!cookieFinder.retrieve(name, &cookie)) - return NULL; - return cookie; -} - -Cookie *CookieManager::CreateCookie(const char *name, const char *description, CookieAccess access) -{ - Cookie *pCookie = FindCookie(name); - - /* Check if cookie already exists */ - if (pCookie != NULL) - { - /* Update data fields to the provided values */ - UTIL_strncpy(pCookie->description, description, MAX_DESC_LENGTH); - pCookie->access = access; - - return pCookie; - } - - /* First time cookie - Create from scratch */ - pCookie = new Cookie(name, description, access); - - /* Attempt to insert cookie into the db and get its ID num */ - TQueryOp *op = new TQueryOp(Query_InsertCookie, pCookie); - op->m_params.cookie = pCookie; - - cookieFinder.insert(name, pCookie); - cookieList.push_back(pCookie); - - g_ClientPrefs.AddQueryToQueue(op); - - return pCookie; -} - -bool CookieManager::GetCookieValue(Cookie *pCookie, int client, char **value) -{ - CookieData *data = pCookie->data[client]; - - /* Check if a value has been set before */ - if (data == NULL) - { - data = new CookieData(""); - data->parent = pCookie; - clientData[client].push_back(data); - pCookie->data[client] = data; - data->changed = false; - data->timestamp = 0; - } - - *value = &data->value[0]; - - return true; -} - -bool CookieManager::SetCookieValue(Cookie *pCookie, int client, const char *value) -{ - CookieData *data = pCookie->data[client]; - - if (data == NULL) - { - data = new CookieData(value); - data->parent = pCookie; - clientData[client].push_back(data); - pCookie->data[client] = data; - } - else - { - UTIL_strncpy(data->value, value, MAX_VALUE_LENGTH); - } - - data->changed = true; - data->timestamp = time(NULL); - - return true; -} - -void CookieManager::OnClientAuthorized(int client, const char *authstring) -{ - IGamePlayer *player = playerhelpers->GetGamePlayer(client); - - if (player == NULL) - { - return; - } - - connected[client] = true; - statsPending[client] = true; - - g_ClientPrefs.AttemptReconnection(); - - TQueryOp *op = new TQueryOp(Query_SelectData, player->GetSerial()); - UTIL_strncpy(op->m_params.steamId, GetPlayerCompatAuthId(player), MAX_NAME_LENGTH); - - g_ClientPrefs.AddQueryToQueue(op); -} - -void CookieManager::OnClientDisconnecting(int client) -{ - connected[client] = false; - statsLoaded[client] = false; - statsPending[client] = false; - - CookieData *current = NULL; - - g_ClientPrefs.AttemptReconnection(); - - /* Save this cookie to the database */ - IGamePlayer *player = playerhelpers->GetGamePlayer(client); - const char *pAuth = NULL; - int dbId; - - if (player) - { - pAuth = GetPlayerCompatAuthId(player); - g_ClientPrefs.ClearQueryCache(player->GetSerial()); - } - - std::vector &clientvec = clientData[client]; - for (size_t iter = 0; iter < clientvec.size(); ++iter) - { - current = clientvec[iter]; - dbId = current->parent->dbid; - - if (player == NULL || pAuth == NULL || !current->changed || dbId == -1) - { - current->parent->data[client] = NULL; - delete current; - continue; - } - - TQueryOp *op = new TQueryOp(Query_InsertData, client); - - UTIL_strncpy(op->m_params.steamId, pAuth, MAX_NAME_LENGTH); - op->m_params.cookieId = dbId; - op->m_params.data = current; - - g_ClientPrefs.AddQueryToQueue(op); - - current->parent->data[client] = NULL; - } - - clientvec.clear(); -} - -void CookieManager::ClientConnectCallback(int serial, IQuery *data) -{ - int client; - - /* Check validity of client */ - if ((client = playerhelpers->GetClientFromSerial(serial)) == 0) - { - return; - } - statsPending[client] = false; - - IResultSet *results; - /* Check validity of results */ - if (data == NULL || (results = data->GetResultSet()) == NULL) - { - return; - } - - CookieData *pData; - IResultRow *row; - unsigned int timestamp; - CookieAccess access; - - while (results->MoreRows() && ((row = results->FetchRow()) != NULL)) - { - const char *name = ""; - row->GetString(0, &name, NULL); - - const char *value = ""; - row->GetString(1, &value, NULL); - - pData = new CookieData(value); - pData->changed = false; - - pData->timestamp = (row->GetInt(4, (int *)×tamp) == DBVal_Data) ? timestamp : 0; - - Cookie *parent = FindCookie(name); - - if (parent == NULL) - { - const char *desc = ""; - row->GetString(2, &desc, NULL); - - access = CookieAccess_Public; - row->GetInt(3, (int *)&access); - - parent = CreateCookie(name, desc, access); - } - - pData->parent = parent; - parent->data[client] = pData; - clientData[client].push_back(pData); - } - - statsLoaded[client] = true; - - cookieDataLoadedForward->PushCell(client); - cookieDataLoadedForward->Execute(NULL); -} - -void CookieManager::InsertCookieCallback(Cookie *pCookie, int dbId) -{ - if (dbId > 0) - { - pCookie->dbid = dbId; - return; - } - - TQueryOp *op = new TQueryOp(Query_SelectId, pCookie); - /* Put the cookie name into the steamId field to save space - Make sure we remember that it's there */ - UTIL_strncpy(op->m_params.steamId, pCookie->name, MAX_NAME_LENGTH); - g_ClientPrefs.AddQueryToQueue(op); -} - -void CookieManager::SelectIdCallback(Cookie *pCookie, IQuery *data) -{ - IResultSet *results; - - if (data == NULL || (results = data->GetResultSet()) == NULL) - { - return; - } - - IResultRow *row = results->FetchRow(); - - if (row == NULL) - { - return; - } - - row->GetInt(0, &pCookie->dbid); -} - -bool CookieManager::AreClientCookiesCached(int client) -{ - return statsLoaded[client]; -} - -bool CookieManager::AreClientCookiesPending(int client) -{ - return statsPending[client]; -} - -void CookieManager::OnPluginDestroyed(IPlugin *plugin) -{ - std::vector *pList; - - if (plugin->GetProperty("SettingsMenuItems", (void **)&pList, true)) - { - std::vector &menuitems = (*pList); - char *name; - ItemDrawInfo draw; - const char *info; - AutoMenuData * data; - unsigned itemcount; - - for (size_t p_iter = 0; p_iter < menuitems.size(); ++p_iter) - { - name = menuitems[p_iter]; - itemcount = clientMenu->GetItemCount(); - //remove from this plugins list - for (unsigned int i=0; i < itemcount; i++) - { - info = clientMenu->GetItemInfo(i, &draw); - - if (info == NULL) - { - continue; - } - - if (strcmp(draw.display, name) == 0) - { - data = (AutoMenuData *)strtoul(info, NULL, 16); - - if (data->handler->forward != NULL) - { - forwards->ReleaseForward(data->handler->forward); - } - delete data->handler; - delete data; - - clientMenu->RemoveItem(i); - break; - } - } - - delete [] name; - } - - menuitems.clear(); - } -} - -bool CookieManager::GetCookieTime(Cookie *pCookie, int client, time_t *value) -{ - CookieData *data = pCookie->data[client]; - - /* Check if a value has been set before */ - if (data == NULL) - { - return false; - } - - *value = data->timestamp; - - return true; -} diff --git a/extensions/clientprefs/cookie.h b/extensions/clientprefs/cookie.h deleted file mode 100644 index 10c9df3ca6..0000000000 --- a/extensions/clientprefs/cookie.h +++ /dev/null @@ -1,149 +0,0 @@ -/** - * vim: set ts=4 sw=4 tw=99 noet : - * ============================================================================= - * SourceMod Client Preferences Extension - * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#ifndef _INCLUDE_SOURCEMOD_CLIENTPREFS_COOKIE_H_ -#define _INCLUDE_SOURCEMOD_CLIENTPREFS_COOKIE_H_ - -#include "extension.h" -#include "am-vector.h" -#include - -#define MAX_NAME_LENGTH 30 -#define MAX_DESC_LENGTH 255 -#define MAX_VALUE_LENGTH 100 - -enum CookieAccess -{ - CookieAccess_Public, /**< Visible and Changeable by users */ - CookieAccess_Protected, /**< Read only to users */ - CookieAccess_Private, /**< Completely hidden cookie */ -}; - -struct Cookie; - -struct CookieData -{ - CookieData(const char *value) - { - UTIL_strncpy(this->value, value, MAX_VALUE_LENGTH); - } - - char value[MAX_VALUE_LENGTH+1]; - bool changed; - time_t timestamp; - Cookie *parent; -}; - -struct Cookie -{ - Cookie(const char *name, const char *description, CookieAccess access) - { - UTIL_strncpy(this->name, name, MAX_NAME_LENGTH); - UTIL_strncpy(this->description, description, MAX_DESC_LENGTH); - - this->access = access; - - dbid = -1; - - for (int i=0; i<=SM_MAXPLAYERS; i++) - data[i] = NULL; - } - - ~Cookie() - { - for (int i=0; i<=SM_MAXPLAYERS; i++) - { - if (data[i] != NULL) - delete data[i]; - } - } - - char name[MAX_NAME_LENGTH+1]; - char description[MAX_DESC_LENGTH+1]; - int dbid; - CookieData *data[SM_MAXPLAYERS+1]; - CookieAccess access; - - static inline bool matches(const char *name, const Cookie *cookie) - { - return strcmp(name, cookie->name) == 0; - } - static inline uint32_t hash(const detail::CharsAndLength &key) - { - return key.hash(); - } -}; - -class CookieManager : public IClientListener, public IPluginsListener -{ -public: - CookieManager(); - ~CookieManager(); - - void OnClientAuthorized(int client, const char *authstring); - void OnClientDisconnecting(int client); - - bool GetCookieValue(Cookie *pCookie, int client, char **value); - bool SetCookieValue(Cookie *pCookie, int client, const char *value); - bool GetCookieTime(Cookie *pCookie, int client, time_t *value); - - void Unload(); - - void ClientConnectCallback(int serial, IQuery *data); - void InsertCookieCallback(Cookie *pCookie, int dbId); - void SelectIdCallback(Cookie *pCookie, IQuery *data); - - Cookie *FindCookie(const char *name); - Cookie *CreateCookie(const char *name, const char *description, CookieAccess access); - - bool AreClientCookiesCached(int client); - - void OnPluginDestroyed(IPlugin *plugin); - - bool AreClientCookiesPending(int client); - -public: - IForward *cookieDataLoadedForward; - std::vector cookieList; - IBaseMenu *clientMenu; - -private: - NameHashSet cookieFinder; - std::vector clientData[SM_MAXPLAYERS+1]; - - bool connected[SM_MAXPLAYERS+1]; - bool statsLoaded[SM_MAXPLAYERS+1]; - bool statsPending[SM_MAXPLAYERS+1]; -}; - -extern CookieManager g_CookieManager; - -#endif // _INCLUDE_SOURCEMOD_CLIENTPREFS_COOKIE_H_ diff --git a/extensions/clientprefs/extension.cpp b/extensions/clientprefs/extension.cpp deleted file mode 100644 index 12c24ae7e3..0000000000 --- a/extensions/clientprefs/extension.cpp +++ /dev/null @@ -1,551 +0,0 @@ -/** - * vim: set ts=4 sw=4 tw=99 noet: - * ============================================================================= - * SourceMod Client Preferences Extension - * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#include -#include "extension.h" - -using namespace ke; - -/** - * @file extension.cpp - * @brief Implement extension code here. - */ - -ClientPrefs g_ClientPrefs; /**< Global singleton for extension's main interface */ - -SMEXT_LINK(&g_ClientPrefs); - -HandleType_t g_CookieType = 0; -CookieTypeHandler g_CookieTypeHandler; - -HandleType_t g_CookieIterator = 0; -CookieIteratorHandler g_CookieIteratorHandler; -DbDriver g_DriverType; - -bool ClientPrefs::SDK_OnLoad(char *error, size_t maxlength, bool late) -{ - DBInfo = dbi->FindDatabaseConf("clientprefs"); - - if (DBInfo == NULL) - { - DBInfo = dbi->FindDatabaseConf("storage-local"); - if (DBInfo == NULL) - { - ke::SafeStrcpy(error, maxlength, "Could not find any suitable database configs"); - return false; - } - } - - if (DBInfo->driver && DBInfo->driver[0] != '\0') - { - Driver = dbi->FindOrLoadDriver(DBInfo->driver); - } - else - { - Driver = dbi->GetDefaultDriver(); - } - - if (Driver == NULL) - { - ke::SafeSprintf(error, maxlength, "Could not load DB Driver \"%s\"", DBInfo->driver); - return false; - } - - databaseLoading = true; - TQueryOp *op = new TQueryOp(Query_Connect, 0); - dbi->AddToThreadQueue(op, PrioQueue_High); - - dbi->AddDependency(myself, Driver); - - sharesys->AddNatives(myself, g_ClientPrefNatives); - sharesys->RegisterLibrary(myself, "clientprefs"); - identity = sharesys->CreateIdentity(sharesys->CreateIdentType("ClientPrefs"), this); - g_CookieManager.cookieDataLoadedForward = forwards->CreateForward("OnClientCookiesCached", ET_Ignore, 1, NULL, Param_Cell); - - g_CookieType = handlesys->CreateType("Cookie", - &g_CookieTypeHandler, - 0, - NULL, - NULL, - myself->GetIdentity(), - NULL); - - g_CookieIterator = handlesys->CreateType("CookieIterator", - &g_CookieIteratorHandler, - 0, - NULL, - NULL, - myself->GetIdentity(), - NULL); - - IMenuStyle *style = menus->GetDefaultStyle(); - g_CookieManager.clientMenu = style->CreateMenu(&g_Handler, identity); - g_CookieManager.clientMenu->SetDefaultTitle("Client Settings:"); - - plsys->AddPluginsListener(&g_CookieManager); - - phrases = translator->CreatePhraseCollection(); - phrases->AddPhraseFile("clientprefs.phrases"); - phrases->AddPhraseFile("common.phrases"); - - if (late) - { - this->CatchLateLoadClients(); - } - - return true; -} - -void ClientPrefs::SDK_OnAllLoaded() -{ - playerhelpers->AddClientListener(&g_CookieManager); -} - -bool ClientPrefs::QueryInterfaceDrop(SMInterface *pInterface) -{ - if ((void *)pInterface == (void *)(Database->GetDriver())) - { - return false; - } - - return true; -} - -void ClientPrefs::NotifyInterfaceDrop(SMInterface *pInterface) -{ - if (Database && (void *)pInterface == (void *)(Database->GetDriver())) - Database = NULL; -} - -void ClientPrefs::SDK_OnDependenciesDropped() -{ - // At this point, we're guaranteed that DBI has flushed the worker thread - // for us, so no cookies should have outstanding queries. - g_CookieManager.Unload(); - - handlesys->RemoveType(g_CookieType, myself->GetIdentity()); - handlesys->RemoveType(g_CookieIterator, myself->GetIdentity()); - - Database = NULL; - - if (g_CookieManager.cookieDataLoadedForward != NULL) - { - forwards->ReleaseForward(g_CookieManager.cookieDataLoadedForward); - g_CookieManager.cookieDataLoadedForward = NULL; - } - - if (g_CookieManager.clientMenu != NULL) - { - Handle_t menuHandle = g_CookieManager.clientMenu->GetHandle(); - - if (menuHandle != BAD_HANDLE) - { - HandleSecurity sec = HandleSecurity(identity, identity); - HandleError err = handlesys->FreeHandle(menuHandle, &sec); - if (HandleError_None != err) - { - g_pSM->LogError(myself, "Error %d when attempting to free client menu handle", err); - } - } - - g_CookieManager.clientMenu = NULL; - } - - if (phrases != NULL) - { - phrases->Destroy(); - phrases = NULL; - } - - plsys->RemovePluginsListener(&g_CookieManager); - playerhelpers->RemoveClientListener(&g_CookieManager); -} - -void ClientPrefs::OnCoreMapStart(edict_t *pEdictList, int edictCount, int clientMax) -{ - this->AttemptReconnection(); -} - -void ClientPrefs::AttemptReconnection() -{ - if (Database || databaseLoading) - return; /* We're already loading, or have loaded. */ - - g_pSM->LogMessage(myself, "Attempting to reconnect to database..."); - databaseLoading = true; - - TQueryOp *op = new TQueryOp(Query_Connect, 0); - dbi->AddToThreadQueue(op, PrioQueue_High); - - this->CatchLateLoadClients(); /* DB reconnection, we should check if we missed anyone... */ -} - -void ClientPrefs::DatabaseConnect() -{ - char error[256]; - int errCode = 0; - - Database = AdoptRef(Driver->Connect(DBInfo, true, error, sizeof(error))); - - if (!Database) - { - g_pSM->LogError(myself, error); - databaseLoading = false; - return; - } - - const char *identifier = Driver->GetIdentifier(); - - if (strcmp(identifier, "sqlite") == 0) - { - g_DriverType = Driver_SQLite; - - if (!Database->DoSimpleQuery( - "CREATE TABLE IF NOT EXISTS sm_cookies \ - ( \ - id INTEGER PRIMARY KEY AUTOINCREMENT, \ - name varchar(30) NOT NULL UNIQUE, \ - description varchar(255), \ - access INTEGER \ - )")) - { - g_pSM->LogMessage(myself, "Failed to CreateTable sm_cookies: %s", Database->GetError()); - goto fatal_fail; - } - - if (!Database->DoSimpleQuery( - "CREATE TABLE IF NOT EXISTS sm_cookie_cache \ - ( \ - player varchar(65) NOT NULL, \ - cookie_id int(10) NOT NULL, \ - value varchar(100), \ - timestamp int, \ - PRIMARY KEY (player, cookie_id) \ - )")) - { - g_pSM->LogMessage(myself, "Failed to CreateTable sm_cookie_cache: %s", Database->GetError()); - goto fatal_fail; - } - } - else if (strcmp(identifier, "mysql") == 0) - { - g_DriverType = Driver_MySQL; - - if (!Database->DoSimpleQuery( - "CREATE TABLE IF NOT EXISTS sm_cookies \ - ( \ - id INTEGER unsigned NOT NULL auto_increment, \ - name varchar(30) NOT NULL UNIQUE, \ - description varchar(255), \ - access INTEGER, \ - PRIMARY KEY (id) \ - )")) - { - g_pSM->LogMessage(myself, "Failed to CreateTable sm_cookies: %s", Database->GetError()); - goto fatal_fail; - } - - if (!Database->DoSimpleQuery( - "CREATE TABLE IF NOT EXISTS sm_cookie_cache \ - ( \ - player varchar(65) NOT NULL, \ - cookie_id int(10) NOT NULL, \ - value varchar(100), \ - timestamp int NOT NULL, \ - PRIMARY KEY (player, cookie_id) \ - )")) - { - g_pSM->LogMessage(myself, "Failed to CreateTable sm_cookie_cache: %s", Database->GetError()); - goto fatal_fail; - } - } - else if (strcmp(identifier, "pgsql") == 0) - { - g_DriverType = Driver_PgSQL; - // PostgreSQL supports 'IF NOT EXISTS' as of 9.1 - if (!Database->DoSimpleQuery( - "CREATE TABLE IF NOT EXISTS sm_cookies \ - ( \ - id serial, \ - name varchar(30) NOT NULL UNIQUE, \ - description varchar(255), \ - access INTEGER, \ - PRIMARY KEY (id) \ - )")) - { - g_pSM->LogMessage(myself, "Failed to CreateTable sm_cookies: %s", Database->GetError()); - goto fatal_fail; - } - - if (!Database->DoSimpleQuery( - "CREATE TABLE IF NOT EXISTS sm_cookie_cache \ - ( \ - player varchar(65) NOT NULL, \ - cookie_id int NOT NULL, \ - value varchar(100), \ - timestamp int NOT NULL, \ - PRIMARY KEY (player, cookie_id) \ - )")) - { - g_pSM->LogMessage(myself, "Failed to CreateTable sm_cookie_cache: %s", Database->GetError()); - goto fatal_fail; - } - - if (!Database->DoSimpleQuery( - "CREATE TABLE IF NOT EXISTS sm_cookie_cache \ - ( \ - player varchar(65) NOT NULL, \ - cookie_id int NOT NULL, \ - value varchar(100), \ - timestamp int NOT NULL, \ - PRIMARY KEY (player, cookie_id) \ - )")) - { - g_pSM->LogMessage(myself, "Failed to CreateTable sm_cookie_cache: %s", Database->GetError()); - goto fatal_fail; - } - - if (!Database->DoSimpleQuery( - "CREATE OR REPLACE FUNCTION add_or_update_cookie(in_player VARCHAR(65), in_cookie INT, in_value VARCHAR(100), in_time INT) RETURNS VOID AS \ - $$ \ - BEGIN \ - LOOP \ - UPDATE sm_cookie_cache SET value = in_value, timestamp = in_time WHERE player = in_player AND cookie_id = in_cookie; \ - IF found THEN \ - RETURN; \ - END IF; \ - BEGIN \ - INSERT INTO sm_cookie_cache (player, cookie_id, value, timestamp) VALUES (in_player, in_cookie, in_value, in_time); \ - RETURN; \ - EXCEPTION WHEN unique_violation THEN \ - END; \ - END LOOP; \ - END; \ - $$ LANGUAGE plpgsql;")) - { - g_pSM->LogMessage(myself, "Failed to create function add_or_update_cookie: %s", Database->GetError()); - goto fatal_fail; - } - } - else - { - g_pSM->LogError(myself, "Unsupported driver \"%s\"", identifier); - goto fatal_fail; - } - - databaseLoading = false; - - // Need a new scope because of the goto above. - { - std::lock_guard lock(queryLock); - this->ProcessQueryCache(); - } - return; - -fatal_fail: - Database = NULL; - databaseLoading = false; -} - -bool ClientPrefs::AddQueryToQueue(TQueryOp *query) -{ - { - std::lock_guard lock(queryLock); - if (!Database) - { - cachedQueries.push_back(query); - return false; - } - - if (!cachedQueries.empty()) - this->ProcessQueryCache(); - } - - query->SetDatabase(Database); - dbi->AddToThreadQueue(query, PrioQueue_Normal); - return true; -} - -void ClientPrefs::ProcessQueryCache() -{ - if (!Database) - return; - - for (size_t iter = 0; iter < cachedQueries.size(); ++iter) - { - TQueryOp *op = cachedQueries[iter]; - op->SetDatabase(Database); - dbi->AddToThreadQueue(op, PrioQueue_Normal); - } - - cachedQueries.clear(); -} - -const char *GetPlayerCompatAuthId(IGamePlayer *pPlayer) -{ - /* For legacy reasons, OnClientAuthorized gives the Steam2 id here if using Steam auth */ - const char *steamId = pPlayer->GetSteam2Id(); - return steamId ? steamId : pPlayer->GetAuthString(); -} - -void ClientPrefs::CatchLateLoadClients() -{ - IGamePlayer *pPlayer; - for (int i = playerhelpers->GetMaxClients()+1; --i > 0;) - { - if (g_CookieManager.AreClientCookiesPending(i) || g_CookieManager.AreClientCookiesCached(i)) - { - continue; - } - - pPlayer = playerhelpers->GetGamePlayer(i); - - if (!pPlayer || !pPlayer->IsAuthorized()) - { - continue; - } - - g_CookieManager.OnClientAuthorized(i, GetPlayerCompatAuthId(pPlayer)); - } -} - -void ClientPrefs::ClearQueryCache(int serial) -{ - std::lock_guard lock(queryLock); - - for (size_t iter = 0; iter < cachedQueries.size(); ++iter) - { - TQueryOp *op = cachedQueries[iter]; - if (op && op->PullQueryType() == Query_SelectData && op->PullQuerySerial() == serial) - { - op->Destroy(); - cachedQueries.erase(cachedQueries.begin() + iter); - iter--; - } - } -} - -bool Translate(char *buffer, - size_t maxlength, - const char *format, - unsigned int numparams, - size_t *pOutLength, - ...) -{ - va_list ap; - unsigned int i; - const char *fail_phrase; - void *params[MAX_TRANSLATE_PARAMS]; - - if (numparams > MAX_TRANSLATE_PARAMS) - { - assert(false); - return false; - } - - va_start(ap, pOutLength); - for (i = 0; i < numparams; i++) - { - params[i] = va_arg(ap, void *); - } - va_end(ap); - - if (!g_ClientPrefs.phrases->FormatString(buffer, - maxlength, - format, - params, - numparams, - pOutLength, - &fail_phrase)) - { - if (fail_phrase != NULL) - { - g_pSM->LogError(myself, "[SM] Could not find core phrase: %s", fail_phrase); - } - else - { - g_pSM->LogError(myself, "[SM] Unknown fatal error while translating a core phrase."); - } - - return false; - } - - return true; -} - -char * UTIL_strncpy(char * destination, const char * source, size_t num) -{ - if (source == NULL) - { - destination[0] = '\0'; - return destination; - } - - size_t req = strlen(source); - if (!req) - { - destination[0] = '\0'; - return destination; - } - else if (req >= num) - { - req = num-1; - } - - strncpy(destination, source, req); - destination[req] = '\0'; - return destination; -} - -IdentityToken_t *ClientPrefs::GetIdentity() const -{ - return identity; -} - -const char *ClientPrefs::GetExtensionVerString() -{ - return SOURCEMOD_VERSION; -} - -const char *ClientPrefs::GetExtensionDateString() -{ - return SOURCEMOD_BUILD_TIME; -} - -ClientPrefs::ClientPrefs() -{ - Driver = NULL; - databaseLoading = false; - phrases = NULL; - DBInfo = NULL; - - identity = NULL; -} diff --git a/extensions/clientprefs/extension.h b/extensions/clientprefs/extension.h deleted file mode 100644 index 333445c5b9..0000000000 --- a/extensions/clientprefs/extension.h +++ /dev/null @@ -1,206 +0,0 @@ -/** - * vim: set ts=4 sw=4 tw=99 noet: - * ============================================================================= - * SourceMod Client Preferences Extension - * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#ifndef _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ -#define _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ - -#include -#include -#include "smsdk_ext.h" -#include "am-vector.h" - -#include -#include - -char * UTIL_strncpy(char * destination, const char * source, size_t num); - -#include "cookie.h" -#include "menus.h" -#include "query.h" - -enum DbDriver -{ - Driver_MySQL, - Driver_SQLite, - Driver_PgSQL -}; - -#define MAX_TRANSLATE_PARAMS 32 - -class TQueryOp; - -/** - * @brief Sample implementation of the SDK Extension. - * Note: Uncomment one of the pre-defined virtual functions in order to use it. - */ -class ClientPrefs : public SDKExtension -{ -public: - ClientPrefs(); -public: - /** - * @brief This is called after the initial loading sequence has been processed. - * - * @param error Error message buffer. - * @param maxlength Size of error message buffer. - * @param late Whether or not the module was loaded after map load. - * @return True to succeed loading, false to fail. - */ - virtual bool SDK_OnLoad(char *error, size_t maxlength, bool late); - - virtual void SDK_OnDependenciesDropped(); - - /** - * @brief This is called once all known extensions have been loaded. - * Note: It is is a good idea to add natives here, if any are provided. - */ - virtual void SDK_OnAllLoaded(); - - virtual bool QueryInterfaceDrop(SMInterface *pInterface); - - virtual void NotifyInterfaceDrop(SMInterface *pInterface); - - const char *GetExtensionVerString(); - const char *GetExtensionDateString(); - - virtual void OnCoreMapStart(edict_t *pEdictList, int edictCount, int clientMax); - - void DatabaseConnect(); - - bool AddQueryToQueue(TQueryOp *query); - void ProcessQueryCache(); - - void AttemptReconnection(); - void CatchLateLoadClients(); - void ClearQueryCache(int serial); - - /** - * @brief Called when the pause state is changed. - */ - //virtual void SDK_OnPauseChange(bool paused); - - /** - * @brief this is called when Core wants to know if your extension is working. - * - * @param error Error message buffer. - * @param maxlength Size of error message buffer. - * @return True if working, false otherwise. - */ - //virtual bool QueryRunning(char *error, size_t maxlength); -public: -#if defined SMEXT_CONF_METAMOD - /** - * @brief Called when Metamod is attached, before the extension version is called. - * - * @param error Error buffer. - * @param maxlength Maximum size of error buffer. - * @param late Whether or not Metamod considers this a late load. - * @return True to succeed, false to fail. - */ - //virtual bool SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlength, bool late); - - /** - * @brief Called when Metamod is detaching, after the extension version is called. - * NOTE: By default this is blocked unless sent from SourceMod. - * - * @param error Error buffer. - * @param maxlength Maximum size of error buffer. - * @return True to succeed, false to fail. - */ - //virtual bool SDK_OnMetamodUnload(char *error, size_t maxlength); - - /** - * @brief Called when Metamod's pause state is changing. - * NOTE: By default this is blocked unless sent from SourceMod. - * - * @param paused Pause state being set. - * @param error Error buffer. - * @param maxlength Maximum size of error buffer. - * @return True to succeed, false to fail. - */ - //virtual bool SDK_OnMetamodPauseChange(bool paused, char *error, size_t maxlength); -#endif -public: - IdentityToken_t *GetIdentity() const; -public: - IDBDriver *Driver; - ke::RefPtr Database; - IPhraseCollection *phrases; - const DatabaseInfo *DBInfo; - - bool databaseLoading; - -private: - std::vector cachedQueries; - std::mutex queryLock; - IdentityToken_t *identity; -}; - -class CookieTypeHandler : public IHandleTypeDispatch -{ -public: - void OnHandleDestroy(HandleType_t type, void *object) - { - /* No delete needed since Cookies are persistent */ - } -}; - -class CookieIteratorHandler : public IHandleTypeDispatch -{ -public: - void OnHandleDestroy(HandleType_t type, void *object) - { - delete (size_t *)object; - } -}; - -const char *GetPlayerCompatAuthId(IGamePlayer *pPlayer); - -extern sp_nativeinfo_t g_ClientPrefNatives[]; - -extern ClientPrefs g_ClientPrefs; -extern HandleType_t g_CookieType; -extern CookieTypeHandler g_CookieTypeHandler; - -extern HandleType_t g_CookieIterator; -extern CookieIteratorHandler g_CookieIteratorHandler; - -bool Translate(char *buffer, - size_t maxlength, - const char *format, - unsigned int numparams, - size_t *pOutLength, - ...); - -extern DbDriver g_DriverType; - -#endif // _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ - diff --git a/extensions/clientprefs/menus.cpp b/extensions/clientprefs/menus.cpp deleted file mode 100644 index 571781892c..0000000000 --- a/extensions/clientprefs/menus.cpp +++ /dev/null @@ -1,146 +0,0 @@ -/** - * vim: set ts=4 : - * ============================================================================= - * SourceMod Client Preferences Extension - * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#include "menus.h" - -ClientMenuHandler g_Handler; -AutoMenuHandler g_AutoHandler; - -void ClientMenuHandler::OnMenuSelect(IBaseMenu *menu, int client, unsigned int item) -{ - ItemDrawInfo draw; - - const char *info = menu->GetItemInfo(item, &draw); - - AutoMenuData *data = (AutoMenuData *)strtoul(info, NULL, 16); - - if (data->handler->forward != NULL) - { - data->handler->forward->PushCell(client); - data->handler->forward->PushCell(CookieMenuAction_SelectOption); - data->handler->forward->PushCell(data->datavalue); - data->handler->forward->PushString(""); - data->handler->forward->PushCell(0); - data->handler->forward->Execute(NULL); - } - - if (!data->handler->isAutoMenu) - { - return; - } - - IBaseMenu *submenu = menus->GetDefaultStyle()->CreateMenu(&g_AutoHandler, g_ClientPrefs.GetIdentity()); - - char message[256]; - - Translate(message, sizeof(message), "%T:", 2, NULL, "Choose Option", &client); - submenu->SetDefaultTitle(message); - - if (data->type == CookieMenu_YesNo || data->type == CookieMenu_YesNo_Int) - { - Translate(message, sizeof(message), "%T", 2, NULL, "Yes", &client); - submenu->AppendItem(info, message); - - Translate(message, sizeof(message), "%T", 2, NULL, "No", &client); - submenu->AppendItem(info, message); - } - else if (data->type == CookieMenu_OnOff || data->type == CookieMenu_OnOff_Int) - { - Translate(message, sizeof(message), "%T", 2, NULL, "On", &client); - submenu->AppendItem(info, message); - - Translate(message, sizeof(message), "%T", 2, NULL, "Off", &client); - submenu->AppendItem(info, message); - } - - submenu->Display(client, 0, NULL); -} - -unsigned int ClientMenuHandler::OnMenuDisplayItem(IBaseMenu *menu, - int client, - IMenuPanel *panel, - unsigned int item, - const ItemDrawInfo &dr) -{ - ItemDrawInfo draw; - - const char *info = menu->GetItemInfo(item, &draw); - - AutoMenuData *data = (AutoMenuData *)strtoul(info, NULL, 16); - - if (data->handler->forward != NULL) - { - char buffer[100]; - g_pSM->Format(buffer, sizeof(buffer), "%s", dr.display); - - data->handler->forward->PushCell(client); - data->handler->forward->PushCell(CookieMenuAction_DisplayOption); - data->handler->forward->PushCell(data->datavalue); - data->handler->forward->PushStringEx(buffer, sizeof(buffer), SM_PARAM_STRING_COPY, SM_PARAM_COPYBACK); - data->handler->forward->PushCell(sizeof(buffer)); - data->handler->forward->Execute(NULL); - - ItemDrawInfo newdraw(buffer, draw.style); - - return panel->DrawItem(newdraw); - } - - return 0; -} - -void AutoMenuHandler::OnMenuSelect(SourceMod::IBaseMenu *menu, int client, unsigned int item) -{ - static const char settings[CookieMenu_Elements][2][4] = { {"yes", "no"}, {"1", "0"}, {"on", "off"}, {"1", "0"} }; - ItemDrawInfo draw; - - const char *info = menu->GetItemInfo(item, &draw); - - AutoMenuData *data = (AutoMenuData *)strtoul(info, NULL, 16); - - g_CookieManager.SetCookieValue(data->pCookie, client, settings[data->type][item]); - - char message[255]; - char *value; - g_CookieManager.GetCookieValue(data->pCookie, client, &value); - Translate(message, sizeof(message), "[SM] %T", 4, NULL, "Cookie Changed Value", &client, &(data->pCookie->name), value); - - gamehelpers->TextMsg(client, 3, message); -} - -void AutoMenuHandler::OnMenuEnd(IBaseMenu *menu, MenuEndReason reason) -{ - HandleSecurity sec = HandleSecurity(g_ClientPrefs.GetIdentity(), g_ClientPrefs.GetIdentity()); - HandleError err = handlesys->FreeHandle(menu->GetHandle(), &sec); - if (HandleError_None != err) - { - g_pSM->LogError(myself, "Error %d when attempting to free automenu handle", err); - } -} diff --git a/extensions/clientprefs/menus.h b/extensions/clientprefs/menus.h deleted file mode 100644 index c25682d4f0..0000000000 --- a/extensions/clientprefs/menus.h +++ /dev/null @@ -1,104 +0,0 @@ -/** - * vim: set ts=4 : - * ============================================================================= - * SourceMod Client Preferences Extension - * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#ifndef _INCLUDE_SOURCEMOD_CLIENTPREFS_MENUS_H_ -#define _INCLUDE_SOURCEMOD_CLIENTPREFS_MENUS_H_ - -#include "extension.h" -#include "cookie.h" - -enum CookieMenuAction -{ - /** - * An option is being drawn for a menu. - * - * INPUT : Client index and any data if available. - * OUTPUT: Buffer for rendering, maxlength of buffer. - */ - CookieMenuAction_DisplayOption = 0, - - /** - * A menu option has been selected. - * - * INPUT : Client index and any data if available. - */ - CookieMenuAction_SelectOption = 1, -}; - -enum CookieMenu -{ - CookieMenu_YesNo, /**< Yes/No menu with "yes"/"no" results saved into the cookie */ - CookieMenu_YesNo_Int, /**< Yes/No menu with 1/0 saved into the cookie */ - CookieMenu_OnOff, /**< On/Off menu with "on"/"off" results saved into the cookie */ - CookieMenu_OnOff_Int, /**< On/Off menu with 1/0 saved into the cookie */ - CookieMenu_Elements -}; - -struct ItemHandler -{ - IChangeableForward *forward; - CookieMenu autoMenuType; - bool isAutoMenu; -}; - -class ClientMenuHandler : public IMenuHandler -{ - void OnMenuSelect(IBaseMenu *menu, int client, unsigned int item); - unsigned int OnMenuDisplayItem(IBaseMenu *menu, - int client, - IMenuPanel *panel, - unsigned int item, - const ItemDrawInfo &dr); -}; - -class AutoMenuHandler : public IMenuHandler -{ - void OnMenuSelect(IBaseMenu *menu, int client, unsigned int item); - void OnMenuEnd(IBaseMenu *menu, MenuEndReason reason); -}; - -extern ClientMenuHandler g_Handler; -extern AutoMenuHandler g_AutoHandler; - -/* Something went wrong with the includes and made me do this */ -struct Cookie; -enum CookieMenu; -struct ItemHandler; - -struct AutoMenuData -{ - ItemHandler *handler; - Cookie *pCookie; - cell_t datavalue; - CookieMenu type; -}; - -#endif // _INCLUDE_SOURCEMOD_CLIENTPREFS_MENUS_H_ diff --git a/extensions/clientprefs/natives.cpp b/extensions/clientprefs/natives.cpp deleted file mode 100644 index a7b9279940..0000000000 --- a/extensions/clientprefs/natives.cpp +++ /dev/null @@ -1,552 +0,0 @@ -/** - * vim: set ts=4 : - * ============================================================================= - * SourceMod Client Preferences Extension - * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#include "extension.h" -#include "cookie.h" -#include "menus.h" - -cell_t RegClientPrefCookie(IPluginContext *pContext, const cell_t *params) -{ - g_ClientPrefs.AttemptReconnection(); - - char *name; - pContext->LocalToString(params[1], &name); - - if (name[0] == '\0') - { - return pContext->ThrowNativeError("Cannot create preference cookie with no name"); - } - - char *desc; - pContext->LocalToString(params[2], &desc); - - Cookie *pCookie = g_CookieManager.CreateCookie(name, desc, (CookieAccess)params[3]); - - if (!pCookie) - { - return BAD_HANDLE; - } - - return handlesys->CreateHandle(g_CookieType, - pCookie, - pContext->GetIdentity(), - myself->GetIdentity(), - NULL); -} - -cell_t FindClientPrefCookie(IPluginContext *pContext, const cell_t *params) -{ - g_ClientPrefs.AttemptReconnection(); - - char *name; - pContext->LocalToString(params[1], &name); - - Cookie *pCookie = g_CookieManager.FindCookie(name); - - if (!pCookie) - { - return BAD_HANDLE; - } - - return handlesys->CreateHandle(g_CookieType, - pCookie, - pContext->GetIdentity(), - myself->GetIdentity(), - NULL); -} - -size_t IsAuthIdConnected(char *authID) -{ - IGamePlayer *player; - const char *authString; - - for (int playerIndex = playerhelpers->GetMaxClients()+1; --playerIndex > 0;) - { - player = playerhelpers->GetGamePlayer(playerIndex); - if (player == NULL || !player->IsAuthorized()) - { - continue; - } - - if (!strcmp(player->GetAuthString(), authID) - || !strcmp(player->GetSteam2Id(), authID) - || !strcmp(player->GetSteam3Id(), authID) - ) - { - return playerIndex; - } - } - - return 0; -} - -cell_t SetAuthIdCookie(IPluginContext *pContext, const cell_t *params) -{ - g_ClientPrefs.AttemptReconnection(); - - char *steamID; - pContext->LocalToString(params[1], &steamID); - - // convert cookie handle to Cookie* - Handle_t hndl = static_cast(params[2]); - HandleError err; - HandleSecurity sec; - - sec.pOwner = NULL; - sec.pIdentity = myself->GetIdentity(); - - Cookie *pCookie; - - if ((err = handlesys->ReadHandle(hndl, g_CookieType, &sec, (void **)&pCookie)) - != HandleError_None) - { - return pContext->ThrowNativeError("Invalid Cookie handle %x (error %d)", hndl, err); - } - - int i_dbId = pCookie->dbid; - char *value; - pContext->LocalToString(params[3], &value); - - // make sure the steamID isn't currently connected - if (int client = IsAuthIdConnected(steamID)) - { - // use regular code for connected players - return g_CookieManager.SetCookieValue(pCookie, client, value); - } - - // constructor calls strncpy for us - CookieData *payload = new CookieData(value); - - // set changed so players connecting later in during the same map will have the correct value - payload->changed = true; - payload->timestamp = time(NULL); - - // edit database table - TQueryOp *op = new TQueryOp(Query_InsertData, pCookie); - // limit player auth length which doubles for cookie name length - UTIL_strncpy(op->m_params.steamId, steamID, MAX_NAME_LENGTH); - op->m_params.cookieId = i_dbId; - op->m_params.data = payload; - - g_ClientPrefs.AddQueryToQueue(op); - - return 1; -} - -cell_t SetClientPrefCookie(IPluginContext *pContext, const cell_t *params) -{ - g_ClientPrefs.AttemptReconnection(); - - int client = params[1]; - - if ((client < 1) || (client > playerhelpers->GetMaxClients())) - { - return pContext->ThrowNativeError("Client index %d is invalid", client); - } - - Handle_t hndl = static_cast(params[2]); - HandleError err; - HandleSecurity sec; - - sec.pOwner = NULL; - sec.pIdentity = myself->GetIdentity(); - - Cookie *pCookie; - - if ((err = handlesys->ReadHandle(hndl, g_CookieType, &sec, (void **)&pCookie)) - != HandleError_None) - { - return pContext->ThrowNativeError("Invalid Cookie handle %x (error %d)", hndl, err); - } - - char *value; - pContext->LocalToString(params[3], &value); - - return g_CookieManager.SetCookieValue(pCookie, client, value); -} - -cell_t GetClientPrefCookie(IPluginContext *pContext, const cell_t *params) -{ - g_ClientPrefs.AttemptReconnection(); - - int client = params[1]; - - if ((client < 1) || (client > playerhelpers->GetMaxClients())) - { - return pContext->ThrowNativeError("Client index %d is invalid", client); - } - - Handle_t hndl = static_cast(params[2]); - HandleError err; - HandleSecurity sec; - - sec.pOwner = NULL; - sec.pIdentity = myself->GetIdentity(); - - Cookie *pCookie; - - if ((err = handlesys->ReadHandle(hndl, g_CookieType, &sec, (void **)&pCookie)) - != HandleError_None) - { - return pContext->ThrowNativeError("Invalid Cookie handle %x (error %d)", hndl, err); - } - - char *value = NULL; - - g_CookieManager.GetCookieValue(pCookie, client, &value); - - pContext->StringToLocal(params[3], params[4], value); - - return 1; -} - -cell_t AreClientCookiesCached(IPluginContext *pContext, const cell_t *params) -{ - g_ClientPrefs.AttemptReconnection(); - - int client = params[1]; - - if ((client < 1) || (client > playerhelpers->GetMaxClients())) - { - return pContext->ThrowNativeError("Client index %d is invalid", client); - } - - return g_CookieManager.AreClientCookiesCached(client); -} - -cell_t GetCookieAccess(IPluginContext *pContext, const cell_t *params) -{ - g_ClientPrefs.AttemptReconnection(); - - Handle_t hndl = static_cast(params[1]); - HandleError err; - HandleSecurity sec; - - sec.pOwner = NULL; - sec.pIdentity = myself->GetIdentity(); - - Cookie *pCookie; - - if ((err = handlesys->ReadHandle(hndl, g_CookieType, &sec, (void **)&pCookie)) - != HandleError_None) - { - return pContext->ThrowNativeError("Invalid Cookie handle %x (error %d)", hndl, err); - } - - return pCookie->access; -} - -static cell_t GetCookieIterator(IPluginContext *pContext, const cell_t *params) -{ - g_ClientPrefs.AttemptReconnection(); - - size_t *iter = new size_t; - *iter = 0; - - Handle_t hndl = handlesys->CreateHandle(g_CookieIterator, iter, pContext->GetIdentity(), myself->GetIdentity(), NULL); - if (hndl == BAD_HANDLE) - { - delete iter; - } - - return hndl; -} - -static cell_t ReadCookieIterator(IPluginContext *pContext, const cell_t *params) -{ - g_ClientPrefs.AttemptReconnection(); - - size_t *iter; - - Handle_t hndl = static_cast(params[1]); - HandleError err; - HandleSecurity sec; - - sec.pOwner = NULL; - sec.pIdentity = myself->GetIdentity(); - - if ((err = handlesys->ReadHandle(hndl, g_CookieIterator, &sec, (void **)&iter)) - != HandleError_None) - { - return pContext->ThrowNativeError("Invalid Cookie iterator handle %x (error %d)", hndl, err); - } - - if (*iter >= g_CookieManager.cookieList.size()) - { - return 0; - } - - Cookie *pCookie = g_CookieManager.cookieList[(*iter)++]; - - pContext->StringToLocalUTF8(params[2], params[3], pCookie->name, NULL); - pContext->StringToLocalUTF8(params[5], params[6], pCookie->description, NULL); - - cell_t *addr; - pContext->LocalToPhysAddr(params[4], &addr); - *addr = pCookie->access; - - return 1; -} - -cell_t ShowSettingsMenu(IPluginContext *pContext, const cell_t *params) -{ - g_ClientPrefs.AttemptReconnection(); - - char message[256]; - Translate(message, sizeof(message), "%T:", 2, NULL, "Client Settings", ¶ms[1]); - - g_CookieManager.clientMenu->SetDefaultTitle(message); - g_CookieManager.clientMenu->Display(params[1], 0, NULL); - - return 0; -} - -cell_t AddSettingsMenuItem(IPluginContext *pContext, const cell_t *params) -{ - g_ClientPrefs.AttemptReconnection(); - - char *display; - pContext->LocalToString(params[3], &display); - - /* Register a callback */ - ItemHandler *pItem = new ItemHandler; - pItem->isAutoMenu = false; - pItem->forward = forwards->CreateForwardEx(NULL, ET_Ignore, 5, NULL, Param_Cell, Param_Cell, Param_Cell, Param_String, Param_Cell); - - pItem->forward->AddFunction(pContext, static_cast(params[1])); - - char info[20]; - AutoMenuData *data = new AutoMenuData; - data->datavalue = params[2]; - data->handler = pItem; - g_pSM->Format(info, sizeof(info), "%x", data); - - ItemDrawInfo draw(display, 0); - - g_CookieManager.clientMenu->AppendItem(info, draw); - - /* Track this in case the plugin unloads */ - - IPlugin *pPlugin = plsys->FindPluginByContext(pContext->GetContext()); - std::vector *pList = NULL; - - if (!pPlugin->GetProperty("SettingsMenuItems", (void **)&pList, false) || !pList) - { - pList = new std::vector; - pPlugin->SetProperty("SettingsMenuItems", pList); - } - - char *copyarray = new char[strlen(display)+1]; - g_pSM->Format(copyarray, strlen(display)+1, "%s", display); - - pList->push_back(copyarray); - - return 0; -} - -cell_t AddSettingsPrefabMenuItem(IPluginContext *pContext, const cell_t *params) -{ - g_ClientPrefs.AttemptReconnection(); - - Handle_t hndl = static_cast(params[1]); - HandleError err; - HandleSecurity sec; - - sec.pOwner = NULL; - sec.pIdentity = myself->GetIdentity(); - - Cookie *pCookie; - - if ((err = handlesys->ReadHandle(hndl, g_CookieType, &sec, (void **)&pCookie)) - != HandleError_None) - { - return pContext->ThrowNativeError("Invalid Cookie handle %x (error %d)", hndl, err); - } - - /* Register a callback */ - ItemHandler *pItem = new ItemHandler; - pItem->isAutoMenu = true; - pItem->autoMenuType = (CookieMenu)params[2]; - - - /* User passed a function id for a callback */ - if (params[4] != -1) - { - pItem->forward = forwards->CreateForwardEx(NULL, ET_Ignore, 5, NULL, Param_Cell, Param_Cell, Param_Cell, Param_String, Param_Cell); - pItem->forward->AddFunction(pContext, static_cast(params[4])); - } - else - { - pItem->forward = NULL; - } - - char *display; - pContext->LocalToString(params[3], &display); - - ItemDrawInfo draw(display, 0); - - char info[20]; - AutoMenuData *data = new AutoMenuData; - data->datavalue = params[5]; - data->pCookie = pCookie; - data->type = (CookieMenu)params[2]; - data->handler = pItem; - g_pSM->Format(info, sizeof(info), "%x", data); - - g_CookieManager.clientMenu->AppendItem(info, draw); - - /* Track this in case the plugin unloads */ - - IPlugin *pPlugin = plsys->FindPluginByContext(pContext->GetContext()); - std::vector *pList = NULL; - - if (!pPlugin->GetProperty("SettingsMenuItems", (void **)&pList, false) || !pList) - { - pList = new std::vector; - pPlugin->SetProperty("SettingsMenuItems", pList); - } - - char *copyarray = new char[strlen(display)+1]; - g_pSM->Format(copyarray, strlen(display)+1, "%s", display); - - pList->push_back(copyarray); - - return 0; -} - -cell_t GetClientCookieTime(IPluginContext *pContext, const cell_t *params) -{ - g_ClientPrefs.AttemptReconnection(); - - Handle_t hndl = static_cast(params[2]); - HandleError err; - HandleSecurity sec; - - sec.pOwner = NULL; - sec.pIdentity = myself->GetIdentity(); - - Cookie *pCookie; - - if ((err = handlesys->ReadHandle(hndl, g_CookieType, &sec, (void **)&pCookie)) - != HandleError_None) - { - return pContext->ThrowNativeError("Invalid Cookie handle %x (error %d)", hndl, err); - } - - time_t value; - - if (!g_CookieManager.GetCookieTime(pCookie, params[1], &value)) - { - return 0; - } - - return value; -} - -static cell_t Cookie_Set(IPluginContext *pContext, const cell_t *params) -{ - // This version takes (handle, client, value). The original is (client, handle, value). - const cell_t new_params[4] = { - 3, - params[2], - params[1], - params[3] - }; - - return SetClientPrefCookie(pContext, new_params); -} - -static cell_t Cookie_Get(IPluginContext *pContext, const cell_t *params) -{ - // This verson takes (handle, client, buffer, maxlen). The original is (client, handle, buffer, maxlen). - const cell_t new_params[5] = { - 4, - params[2], - params[1], - params[3], - params[4] - }; - - return GetClientPrefCookie(pContext, new_params); -} - -static cell_t Cookie_SetByAuthId(IPluginContext *pContext, const cell_t *params) -{ - // This version takes (handle, authid, value). The original is (authid, handle, value). - const cell_t new_params[4] = { - 3, - params[2], - params[1], - params[3] - }; - - return SetAuthIdCookie(pContext, new_params); -} - -static cell_t Cookie_GetClientTime(IPluginContext *pContext, const cell_t *params) -{ - // This version takes (handle, client). The original is (client, handle) - const cell_t new_params[3] = { - 2, - params[2], - params[1], - }; - - return GetClientCookieTime(pContext, new_params); -} - -sp_nativeinfo_t g_ClientPrefNatives[] = -{ - {"RegClientCookie", RegClientPrefCookie}, - {"FindClientCookie", FindClientPrefCookie}, - {"SetClientCookie", SetClientPrefCookie}, - {"SetAuthIdCookie", SetAuthIdCookie}, - {"GetClientCookie", GetClientPrefCookie}, - {"AreClientCookiesCached", AreClientCookiesCached}, - {"GetCookieAccess", GetCookieAccess}, - {"ReadCookieIterator", ReadCookieIterator}, - {"GetCookieIterator", GetCookieIterator}, - {"ShowCookieMenu", ShowSettingsMenu}, - {"SetCookieMenuItem", AddSettingsMenuItem}, - {"SetCookiePrefabMenu", AddSettingsPrefabMenuItem}, - {"GetClientCookieTime", GetClientCookieTime}, - - {"Cookie.Cookie", RegClientPrefCookie}, - {"Cookie.Find", FindClientPrefCookie}, - {"Cookie.Set", Cookie_Set}, - {"Cookie.Get", Cookie_Get}, - {"Cookie.SetByAuthId", Cookie_SetByAuthId}, - {"Cookie.SetPrefabMenu", AddSettingsPrefabMenuItem}, - {"Cookie.GetClientTime", Cookie_GetClientTime}, - {"Cookie.AccessLevel.get", GetCookieAccess}, - - {NULL, NULL} -}; diff --git a/extensions/clientprefs/query.cpp b/extensions/clientprefs/query.cpp deleted file mode 100644 index a559b0abd9..0000000000 --- a/extensions/clientprefs/query.cpp +++ /dev/null @@ -1,346 +0,0 @@ -/** - * vim: set ts=4 : - * ============================================================================= - * SourceMod Client Preferences Extension - * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#include "query.h" - - -void TQueryOp::RunThinkPart() -{ - //handler for threaded sql queries - switch (m_type) - { - case Query_InsertCookie: - { - g_CookieManager.InsertCookieCallback(m_pCookie, m_insertId); - break; - } - - case Query_SelectData: - { - g_CookieManager.ClientConnectCallback(m_serial, m_pResult); - break; - } - - case Query_SelectId: - { - g_CookieManager.SelectIdCallback(m_pCookie, m_pResult); - break; - } - - case Query_Connect: - { - return; - } - - default: - { - break; - } - } -} - -void TQueryOp::RunThreadPart() -{ - if (m_type == Query_Connect) - { - g_ClientPrefs.DatabaseConnect(); - return; - } - - assert(m_database != NULL); - /* I don't think this is needed anymore... keeping for now. */ - m_database->LockForFullAtomicOperation(); - if (!BindParamsAndRun()) - { - g_pSM->LogError(myself, - "Failed SQL Query, Error: \"%s\" (Query id %i - serial %i)", - m_database->GetError(), - m_type, - m_serial); - } - - m_database->UnlockFromFullAtomicOperation(); -} - -IDBDriver *TQueryOp::GetDriver() -{ - return m_driver; -} - -IdentityToken_t *TQueryOp::GetOwner() -{ - return myself->GetIdentity(); -} - -void TQueryOp::Destroy() -{ - if (m_pResult != NULL) - { - m_pResult->Destroy(); - } - delete this; -} - -TQueryOp::TQueryOp(enum querytype type, int serial) -{ - m_type = type; - m_serial = serial; - m_database = NULL; - m_driver = NULL; - m_insertId = -1; - m_pResult = NULL; -} - -TQueryOp::TQueryOp(enum querytype type, Cookie *cookie) -{ - m_type = type; - m_pCookie = cookie; - m_database = NULL; - m_driver = NULL; - m_insertId = -1; - m_pResult = NULL; - m_serial = 0; -} - -void TQueryOp::SetDatabase(IDatabase *db) -{ - m_database = db; - m_driver = m_database->GetDriver(); -} - -bool TQueryOp::BindParamsAndRun() -{ - size_t ignore; - char query[2048]; - - switch (m_type) - { - case Query_InsertCookie: - { - char safe_name[MAX_NAME_LENGTH*2 + 1]; - char safe_desc[MAX_DESC_LENGTH*2 + 1]; - - m_database->QuoteString(m_params.cookie->name, - safe_name, - sizeof(safe_name), - &ignore); - m_database->QuoteString(m_params.cookie->description, - safe_desc, - sizeof(safe_desc), - &ignore); - - if (g_DriverType == Driver_MySQL) - { - g_pSM->Format(query, - sizeof(query), - "INSERT IGNORE INTO sm_cookies (name, description, access) \ - VALUES (\"%s\", \"%s\", %d)", - safe_name, - safe_desc, - m_params.cookie->access); - } - else if (g_DriverType == Driver_SQLite) - { - g_pSM->Format(query, - sizeof(query), - "INSERT OR IGNORE INTO sm_cookies (name, description, access) \ - VALUES ('%s', '%s', %d)", - safe_name, - safe_desc, - m_params.cookie->access); - } - else if (g_DriverType == Driver_PgSQL) - { - // just insert. Returns error on already exists, so ignore the error. - g_pSM->Format(query, - sizeof(query), - "INSERT INTO sm_cookies (name, description, access) \ - VALUES ('%s', '%s', %d)", - safe_name, - safe_desc, - m_params.cookie->access); - } - - if (!m_database->DoSimpleQuery(query)) - { - return false; - } - - m_insertId = m_database->GetInsertID(); - - return true; - } - - case Query_SelectData: - { - char safe_str[128]; - - m_database->QuoteString(m_params.steamId, safe_str, sizeof(safe_str), &ignore); - - g_pSM->Format(query, - sizeof(query), - "SELECT sm_cookies.name, sm_cookie_cache.value, sm_cookies.description, \ - sm_cookies.access, sm_cookie_cache.timestamp \ - FROM sm_cookies \ - JOIN sm_cookie_cache \ - ON sm_cookies.id = sm_cookie_cache.cookie_id \ - WHERE player = '%s'", - safe_str); - - m_pResult = m_database->DoQuery(query); - - return (m_pResult != NULL); - } - - case Query_InsertData: - { - char safe_id[128]; - char safe_val[MAX_VALUE_LENGTH*2 + 1]; - - m_database->QuoteString(m_params.steamId, - safe_id, - sizeof(safe_id), - &ignore); - m_database->QuoteString(m_params.data->value, - safe_val, - sizeof(safe_val), - &ignore); - - if (g_DriverType == Driver_MySQL) - { - g_pSM->Format(query, - sizeof(query), - "INSERT INTO sm_cookie_cache (player, cookie_id, value, timestamp) \ - VALUES (\"%s\", %d, \"%s\", %d) \ - ON DUPLICATE KEY UPDATE \ - value = \"%s\", timestamp = %d", - safe_id, - m_params.cookieId, - safe_val, - (unsigned int)m_params.data->timestamp, - safe_val, - (unsigned int)m_params.data->timestamp); - } - else if (g_DriverType == Driver_SQLite) - { - g_pSM->Format(query, - sizeof(query), - "INSERT OR REPLACE INTO sm_cookie_cache \ - (player, cookie_id, value, timestamp) \ - VALUES ('%s', %d, '%s', %d)", - safe_id, - m_params.cookieId, - safe_val, - (unsigned int)m_params.data->timestamp); - } - else if (g_DriverType == Driver_PgSQL) - { - // Using a PL/Pgsql function, called add_or_update_cookie(), - // since Postgres does not have an 'OR REPLACE' functionality. - g_pSM->Format(query, - sizeof(query), - "SELECT add_or_update_cookie ('%s', %d, '%s', %d)", - safe_id, - m_params.cookieId, - safe_val, - (unsigned int)m_params.data->timestamp); - } - - if (!m_database->DoSimpleQuery(query)) - { - return false; - } - - m_insertId = m_database->GetInsertID(); - - return true; - } - - case Query_SelectId: - { - char safe_name[MAX_NAME_LENGTH*2 + 1]; - - /* the steamId var was actually used to store the name of the cookie - Save duplicating vars */ - m_database->QuoteString(m_params.steamId, - safe_name, - sizeof(safe_name), - &ignore); - - g_pSM->Format(query, - sizeof(query), - "SELECT id FROM sm_cookies WHERE name = '%s'", - safe_name); - - m_pResult = m_database->DoQuery(query); - - return (m_pResult != NULL); - } - - default: - { - break; - } - - } - - assert(false); - - return false; -} - -querytype TQueryOp::PullQueryType() -{ - return m_type; -} - -int TQueryOp::PullQuerySerial() -{ - return m_serial; -} - -ParamData::~ParamData() -{ - if (data) - { - /* Data is only ever passed in a client disconnect query and always needs to be deleted */ - delete data; - data = NULL; - } -} - -ParamData::ParamData() -{ - cookie = NULL; - data = NULL; - steamId[0] = '\0'; - cookieId = 0; -} - diff --git a/extensions/clientprefs/query.h b/extensions/clientprefs/query.h deleted file mode 100644 index 31cdf55d01..0000000000 --- a/extensions/clientprefs/query.h +++ /dev/null @@ -1,116 +0,0 @@ -/** - * vim: set ts=4 : - * ============================================================================= - * SourceMod Client Preferences Extension - * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#ifndef _INCLUDE_SOURCEMOD_CLIENTPREFS_QUERY_H_ -#define _INCLUDE_SOURCEMOD_CLIENTPREFS_QUERY_H_ - -#include "extension.h" -#include "cookie.h" -#include "sh_string.h" - -enum querytype -{ - Query_InsertCookie = 0, - Query_SelectData, - Query_InsertData, - Query_SelectId, - Query_Connect, -}; - -struct Cookie; -struct CookieData; -#define MAX_NAME_LENGTH 30 - -/* This stores all the info required for our param binding until the thread is executed */ -struct ParamData -{ - ParamData(); - - ~ParamData(); - - /* Contains a name, description and access for InsertCookie queries */ - Cookie *cookie; - /* A clients steamid - Used for most queries - Doubles as storage for the cookie name*/ - char steamId[MAX_NAME_LENGTH]; - - int cookieId; - CookieData *data; -}; - -class TQueryOp : public IDBThreadOperation -{ -public: - TQueryOp(enum querytype type, int serial); - TQueryOp(enum querytype type, Cookie *cookie); - ~TQueryOp() {} - - IDBDriver *GetDriver(); - IdentityToken_t *GetOwner(); - - void SetDatabase(IDatabase *db); - - void Destroy(); - - void RunThreadPart(); - /* Thread has been cancelled due to driver unloading. Nothing else to do? */ - void CancelThinkPart() {} - void RunThinkPart(); - - bool BindParamsAndRun(); - - /* Params to be bound */ - ParamData m_params; - - inline IDatabase *GetDB() - { - return m_database; - } - -public: - querytype PullQueryType(); - int PullQuerySerial(); - -private: - IDatabase *m_database; - IDBDriver *m_driver; - IQuery *m_pResult; - - /* Query type */ - enum querytype m_type; - - /* Data to be passed to the callback */ - int m_serial; - int m_insertId; - Cookie *m_pCookie; -}; - - -#endif // _INCLUDE_SOURCEMOD_CLIENTPREFS_QUERY_H_ diff --git a/extensions/clientprefs/smsdk_config.h b/extensions/clientprefs/smsdk_config.h deleted file mode 100644 index 9a7f0c63f1..0000000000 --- a/extensions/clientprefs/smsdk_config.h +++ /dev/null @@ -1,80 +0,0 @@ -/** - * vim: set ts=4 : - * ============================================================================= - * SourceMod Client Preferences Extension - * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#ifndef _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ -#define _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ - -/** - * @file smsdk_config.h - * @brief Contains macros for configuring basic extension information. - */ - -/* Basic information exposed publicly */ -#define SMEXT_CONF_NAME "Client Preferences" -#define SMEXT_CONF_DESCRIPTION "Saves client preference settings" -#define SMEXT_CONF_VERSION "" -#define SMEXT_CONF_AUTHOR "AlliedModders" -#define SMEXT_CONF_URL "http://www.sourcemod.net/" -#define SMEXT_CONF_LOGTAG "CLIENTPREFS" -#define SMEXT_CONF_LICENSE "GPL" -#define SMEXT_CONF_DATESTRING "" - -/** - * @brief Exposes plugin's main interface. - */ -#define SMEXT_LINK(name) SDKExtension *g_pExtensionIface = name; - -/** - * @brief Sets whether or not this plugin required Metamod. - * NOTE: Uncomment to enable, comment to disable. - */ -//#define SMEXT_CONF_METAMOD - -/** Enable interfaces you want to use here by uncommenting lines */ -#define SMEXT_ENABLE_FORWARDSYS -#define SMEXT_ENABLE_HANDLESYS -#define SMEXT_ENABLE_PLAYERHELPERS -#define SMEXT_ENABLE_DBMANAGER -//#define SMEXT_ENABLE_GAMECONF -//#define SMEXT_ENABLE_MEMUTILS -#define SMEXT_ENABLE_GAMEHELPERS -//#define SMEXT_ENABLE_TIMERSYS -//#define SMEXT_ENABLE_THREADER -//#define SMEXT_ENABLE_LIBSYS -#define SMEXT_ENABLE_MENUS -//#define SMEXT_ENABLE_ADTFACTORY -#define SMEXT_ENABLE_PLUGINSYS -//#define SMEXT_ENABLE_ADMINSYS -//#define SMEXT_ENABLE_TEXTPARSERS -//#define SMEXT_ENABLE_USERMSGS -#define SMEXT_ENABLE_TRANSLATOR - -#endif // _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ diff --git a/extensions/clientprefs/version.rc b/extensions/clientprefs/version.rc deleted file mode 100644 index 0b13c606b9..0000000000 --- a/extensions/clientprefs/version.rc +++ /dev/null @@ -1,104 +0,0 @@ -// Microsoft Visual C++ generated resource script. -// -//#include "resource.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "winres.h" - -#include - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (U.S.) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -#ifdef _WIN32 -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(1252) -#endif //_WIN32 - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -VS_VERSION_INFO VERSIONINFO - FILEVERSION SM_VERSION_FILE - PRODUCTVERSION SM_VERSION_FILE - FILEFLAGSMASK 0x17L -#ifdef _DEBUG - FILEFLAGS 0x1L -#else - FILEFLAGS 0x0L -#endif - FILEOS 0x4L - FILETYPE 0x2L - FILESUBTYPE 0x0L -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "000004b0" - BEGIN - VALUE "Comments", "Client Preferences Extension" - VALUE "FileDescription", "SourceMod Client Preferences Extension" - VALUE "FileVersion", SM_VERSION_STRING - VALUE "InternalName", "SourceMod Client Preferences Extension" - VALUE "LegalCopyright", "Copyright (c) 2004-2008, AlliedModders LLC" - VALUE "OriginalFilename", BINARY_NAME - VALUE "ProductName", "SourceMod Client Preferences Extension" - VALUE "ProductVersion", SM_VERSION_STRING - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x0, 1200 - END -END - - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""winres.h""\r\n" - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - -#endif // English (U.S.) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - diff --git a/plugins/clientprefs.sp b/plugins/clientprefs.sp index d22fa3aa4b..12a6211c2b 100644 --- a/plugins/clientprefs.sp +++ b/plugins/clientprefs.sp @@ -1,174 +1,158 @@ -/** - * vim: set ts=4 : - * ============================================================================= - * SourceMod Map Management Plugin - * Provides all map related functionality, including map changing, map voting, - * and nextmap. - * - * SourceMod (C)2004-2008 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - - -#pragma semicolon 1 -#include -#include - -#pragma newdecls required - -public Plugin myinfo = -{ - name = "Client Preferences", - author = "AlliedModders LLC", - description = "Client preferences and settings menu", - version = SOURCEMOD_VERSION, - url = "http://www.sourcemod.net/" -}; - -public void OnPluginStart() -{ - LoadTranslations("clientprefs.phrases"); - - RegConsoleCmd("sm_cookies", Command_Cookie, "sm_cookies [value]"); - RegConsoleCmd("sm_settings", Command_Settings); -} - -public Action Command_Cookie(int client, int args) -{ - if (args == 0) - { - ReplyToCommand(client, "[SM] Usage: sm_cookies [value]"); - ReplyToCommand(client, "[SM] %t", "Printing Cookie List"); - - /* Show list of cookies */ - Handle iter = GetCookieIterator(); - - char name[30]; - char description[255]; - - PrintToConsole(client, "%t:", "Cookie List"); - - CookieAccess access; - - int count = 1; - - while (ReadCookieIterator(iter, name, sizeof(name), access, description, sizeof(description)) != false) - { - if (access < CookieAccess_Private) - { - PrintToConsole(client, "[%03d] %s - %s", count++, name, description); - } - } - - delete iter; - return Plugin_Handled; - } - - if (client == 0) - { - PrintToServer("%T", "No Console", LANG_SERVER); - return Plugin_Handled; - } - - char name[30]; - - GetCmdArg(1, name, sizeof(name)); - - Handle cookie = FindClientCookie(name); - - if (cookie == null) - { - ReplyToCommand(client, "[SM] %t", "Cookie not Found", name); - return Plugin_Handled; - } - - CookieAccess access = GetCookieAccess(cookie); - - if (access == CookieAccess_Private) - { - ReplyToCommand(client, "[SM] %t", "Cookie not Found", name); - delete cookie; - return Plugin_Handled; - } - - char value[100]; - - if (args == 1) - { - Handle iter = GetCookieIterator(); - - GetClientCookie(client, cookie, value, sizeof(value)); - ReplyToCommand(client, "[SM] %t", "Cookie Value", name, value); - - char CookieName[30]; - char description[255]; - - while (ReadCookieIterator(iter, CookieName, sizeof(CookieName), access, description, sizeof(description)) != false) // We're allowed to re-use access since we're about to return anyways. - { - if (StrEqual(CookieName, name, true)) - { - TrimString(description); - if (description[0] != EOS) - ReplyToCommand(client, "- %s", description); - - break; - } - } - - delete iter; - delete cookie; - return Plugin_Handled; - } - if (access == CookieAccess_Protected) - { - ReplyToCommand(client, "[SM] %t", "Protected Cookie", name); - delete cookie; - return Plugin_Handled; - } - - /* Set the new value of the cookie */ - - GetCmdArg(2, value, sizeof(value)); - - SetClientCookie(client, cookie, value); - delete cookie; - ReplyToCommand(client, "[SM] %t", "Cookie Changed Value", name, value); - - return Plugin_Handled; -} - -public Action Command_Settings(int client, int args) -{ - if (client == 0) - { - PrintToServer("%T", "No Console", LANG_SERVER); - return Plugin_Handled; - } - - ShowCookieMenu(client); - - return Plugin_Handled; -} +#include +#include + +#pragma semicolon 1 +#pragma newdecls required + +Database g_Database = null; + +#include "clientprefs/utils.sp" +#include "clientprefs/menus.sp" +#include "clientprefs/cookies.sp" +#include "clientprefs/commands.sp" +#include "clientprefs/database.sp" +#include "clientprefs/forwards.sp" +#include "clientprefs/natives.sp" + +public Plugin myinfo = +{ + name = "Client Preferences", + author = "AlliedModders LLC", + description = "Saves client preference settings", + version = SOURCEMOD_VERSION, + url = "http://www.sourcemod.net/" +}; + +public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max) +{ + InitMenus(); + InitCookies(); + CreateNatives(); + CreateForwards(); + + RegPluginLibrary("clientprefs"); + return APLRes_Success; +} + +public void OnPluginStart() +{ + LoadTranslations("common.phrases"); + LoadTranslations("clientprefs.phrases"); + + CreateCommands(); + + DB_TryConnect(); +} + +public void OnPluginEnd() +{ + // Try to save player data + for (int i = 1; i <= MaxClients; i++) + { + OnClientDisconnect(i); + } +} + +public void OnMapStart() +{ + DB_TryConnect(); +} + +// Second param is unused +public void OnClientAuthorized(int client) +{ + if (!DB_HasMigrated() || IsFakeClient(client)) + { + return; + } + + SetPlayerDataPending(client, true); + + char steamId2[32]; + GetClientAuthId(client, AuthId_Steam2, steamId2, sizeof(steamId2)); + + DB_SelectPlayerData(client, steamId2); +} + +public void OnClientDisconnect(int client) +{ + if (!IsClientConnected(client) || IsFakeClient(client)) + { + return; + } + + char authId[32]; + + bool hasAuth = GetClientAuthId(client, AuthId_Steam2, authId, sizeof(authId)); + if (!hasAuth) + { + // Unlucky + return; + } + + // TODO: Could this use transactions per player? + StringMapSnapshot snap = GetCookieDataSnapshot(); + + for (int i = 0; i < snap.Length; i++) + { + char name[30]; + snap.GetKey(i, name, sizeof(name)); + + CookieData cookieData; + GetCookieDataByName(name, cookieData); + + if (cookieData.dbId > 0) + { + PlayerData playerData; + GetCookiePlayerData(client, name, playerData); + + DB_InsertPlayerData(authId, cookieData.dbId, playerData.Value); + } + } + + delete snap; + + ClearPlayerData(client); + SetPlayerDataLoaded(client, false); + SetPlayerDataPending(client, false); +} + +void LateLoadClients() +{ + for (int i = 1; i <= MaxClients; i++) + { + if (IsPlayerDataCached(i) || IsPlayerDataPending(i)) + { + continue; + } + + if (!IsClientAuthorized(i)) + { + continue; + } + + OnClientAuthorized(i); + } +} + +void InsertPendingCookies() +{ + StringMapSnapshot snap = GetCookieDataSnapshot(); + + for (int i = 0; i < snap.Length; i++) + { + char name[30]; + snap.GetKey(i, name, sizeof(name)); + + CookieData cookieData; + GetCookieDataByName(name, cookieData); + + // If the database id is not set, this has not yet made it into the db + if (cookieData.dbId == 0) + { + DB_InsertCookie(cookieData.Name, cookieData.Description, cookieData.AccessLevel); + } + } + + delete snap; +} diff --git a/plugins/clientprefs/commands.sp b/plugins/clientprefs/commands.sp new file mode 100644 index 0000000000..c705700fbf --- /dev/null +++ b/plugins/clientprefs/commands.sp @@ -0,0 +1,112 @@ +void CreateCommands() +{ + RegConsoleCmd("sm_cookies", Command_Cookies, "sm_cookies [value]"); + RegConsoleCmd("sm_settings", Command_Settings); +} + +public Action Command_Cookies(int client, int args) +{ + if (args == 0) + { + ReplyToCommand(client, "[SM] Usage: sm_cookies [value]"); + ReplyToCommand(client, "[SM] %t", "Printing Cookie List"); + + PrintToConsole(client, "%t:", "Cookie List"); + + StringMapSnapshot snap = GetCookieDataSnapshot(); + + int count = 1; + + for (int i = 0; i < snap.Length; i++) + { + char name[30]; + snap.GetKey(i, name, sizeof(name)); + + CookieData cookieData; + GetCookieDataByName(name, cookieData); + + if (cookieData.AccessLevel < CookieAccess_Private) + { + PrintToConsole(client, "[%03d] %s - %s", count++, name, cookieData.Description); + } + } + + delete snap; + return Plugin_Handled; + } + + if (client == 0) + { + PrintToServer("%T", "No Console", LANG_SERVER); + return Plugin_Handled; + } + + char name[30]; + GetCmdArg(1, name, sizeof(name)); + + CookieData cookieData; + + bool hasCookieData = GetCookieDataByName(name, cookieData); + if (!hasCookieData) + { + ReplyToCommand(client, "[SM] %t", "Cookie not Found", name); + return Plugin_Handled; + } + + if (cookieData.AccessLevel == CookieAccess_Private) + { + ReplyToCommand(client, "[SM] %t", "Cookie not Found", name); + return Plugin_Handled; + } + + if (args == 1) + { + PlayerData playerData; + + bool hasPlayerData = GetCookiePlayerData(client, name, playerData); + if (!hasPlayerData) + { + // Enum struct strings would default to "" so this is technically an useless branch + ReplyToCommand(client, "[SM] %t", "Cookie Value", name, ""); + return Plugin_Handled; + } + + ReplyToCommand(client, "[SM] %t", "Cookie Value", name, playerData.Value); + + // Eww mutating... + TrimString(cookieData.Description); + + if (cookieData.Description[0]) + { + ReplyToCommand(client, "- %s", cookieData.Description); + } + + return Plugin_Handled; + } + + if (cookieData.AccessLevel == CookieAccess_Protected) + { + ReplyToCommand(client, "[SM] %t", "Protected Cookie", name); + return Plugin_Handled; + } + + char value[100]; + GetCmdArg(2, value, sizeof(value)); + + PlayerData playerData; + GetCookiePlayerData(client, name, playerData); + + playerData.Value = value; + SetPlayerData(client, name, playerData); + + // TODO: Decide on using internal state/funcs vs Plugin API + + ReplyToCommand(client, "[SM] %t", "Cookie Changed Value", name, value); + return Plugin_Handled; +} + +public Action Command_Settings(int client, int args) +{ + DisplaySettingsMenu(client); + return Plugin_Handled; +} diff --git a/plugins/clientprefs/cookies.sp b/plugins/clientprefs/cookies.sp new file mode 100644 index 0000000000..e6f6dc9f2f --- /dev/null +++ b/plugins/clientprefs/cookies.sp @@ -0,0 +1,194 @@ +enum struct CookieData +{ + int dbId; + char Name[COOKIE_MAX_NAME_LENGTH]; + char Description[COOKIE_MAX_DESCRIPTION_LENGTH]; + CookieAccess AccessLevel; +} + +enum struct PlayerData +{ + int Timestamp; + char Value[COOKIE_MAX_VALUE_LENGTH]; +} + +static bool gB_DataLoaded[MAXPLAYERS + 1]; +static bool gB_DataPending[MAXPLAYERS + 1]; + +static StringMap g_Cookies; +static StringMap g_PlayerData[MAXPLAYERS + 1]; + +void InitCookies() +{ + g_Cookies = new StringMap(); + + // MaxClients is not available here, creates potentially unnecessary handles + for (int i = 1; i < sizeof(g_PlayerData); i++) + { + g_PlayerData[i] = new StringMap(); + } +} + +void ClearPlayerData(int client) +{ + g_PlayerData[client].Clear(); +} + +bool IsPlayerDataCached(int client) +{ + return gB_DataLoaded[client]; +} + +bool IsPlayerDataPending(int client) +{ + return gB_DataPending[client]; +} + +void SetCookieData(const char[] name, CookieData data) +{ + g_Cookies.SetArray(name, data, sizeof(data)); +} + +void SetCookieKnownDatabaseId(const char[] name, int id) +{ + CookieData data; + + bool exists = GetCookieDataByName(name, data); + if (!exists) + { + return; + } + + data.dbId = id; + SetCookieData(name, data); +} + +void SetPlayerData(int client, const char[] name, PlayerData playerData) +{ + g_PlayerData[client].SetArray(name, playerData, sizeof(playerData)); +} + +void SetPlayerDataLoaded(int client, bool loaded) +{ + gB_DataLoaded[client] = loaded; +} + +void SetPlayerDataPending(int client, bool pending) +{ + gB_DataPending[client] = pending; +} + +int GetCookieCount() +{ + StringMapSnapshot snap = GetCookieDataSnapshot(); + int count = snap.Length; + + delete snap; + return count; +} + +StringMapSnapshot GetCookieDataSnapshot() +{ + return g_Cookies.Snapshot(); +} + +bool GetCookieDataByName(const char[] name, CookieData foundData) +{ + return g_Cookies.GetArray(name, foundData, sizeof(foundData)); +} + +bool GetCookieDataByIndex(int index, CookieData foundData) +{ + StringMapSnapshot snap = GetCookieDataSnapshot(); + + char name[30]; + snap.GetKey(index, name, sizeof(name)); + + delete snap; + return GetCookieDataByName(name, foundData); +} + +bool GetCookiePlayerData(int client, const char[] name, PlayerData foundData) +{ + return g_PlayerData[client].GetArray(name, foundData, sizeof(foundData)); +} + +int GetIteratorIndexFromConsumerHandle(ArrayList consumerHandle) +{ + return consumerHandle.Get(0); +} + +bool UpdatePlayerCookieValue(int client, const char[] cookieName, const char value[100]) +{ + CookieData cookieData; + + bool hasCookieData = GetCookieDataByName(cookieName, cookieData); + if (!hasCookieData) + { + return false; + } + + PlayerData playerData; + GetCookiePlayerData(client, cookieName, playerData); + + playerData.Value = value; + playerData.Timestamp = GetTime(); + + SetPlayerData(client, cookieName, playerData); + return true; +} + +bool IncrementIteratorIndexForConsumerHandle(ArrayList consumerHandle) +{ + int index = GetIteratorIndexFromConsumerHandle(consumerHandle); + if (index < 0) + { + return false; + } + + consumerHandle.Set(0, index + 1); + return true; +} + +bool GetCookieDataFromConsumerHandle(ArrayList consumerHandle, CookieData foundData) +{ + char name[30]; + consumerHandle.GetString(0, name, sizeof(name)); + + return GetCookieDataByName(name, foundData); +} + +bool GetCookiePlayerDataFromConsumerHandle(ArrayList consumerHandle, int client, PlayerData foundData) +{ + CookieData cookieData; + + bool hasCookieData = GetCookieDataFromConsumerHandle(consumerHandle, cookieData); + if (!hasCookieData) + { + return false; + } + + return GetCookiePlayerData(client, cookieData.Name, foundData); +} + +ArrayList CreateConsumerHandleForIterator(Handle plugin) +{ + ArrayList originalHandle = new ArrayList(1, 1); + originalHandle.Set(0, 0); + + Handle clonedHandle = CloneHandle(originalHandle, plugin); + delete originalHandle; + + return view_as(clonedHandle); +} + +ArrayList CreateConsumerHandleForCookieData(CookieData data, Handle plugin) +{ + ArrayList originalHandle = new ArrayList(ByteCountToCells(30), 1); + originalHandle.SetString(0, data.Name); + + Handle clonedHandle = CloneHandle(originalHandle, plugin); + delete originalHandle; + + return view_as(clonedHandle); +} diff --git a/plugins/clientprefs/database.sp b/plugins/clientprefs/database.sp new file mode 100644 index 0000000000..bae84c714c --- /dev/null +++ b/plugins/clientprefs/database.sp @@ -0,0 +1,470 @@ +static bool HasMigrated = false; +static bool IsConnecting = false; + +bool DB_HasMigrated() +{ + return HasMigrated; +} + +bool DB_IsConnected() +{ + return g_Database != null; +} + +bool DB_IsConnecting() +{ + return IsConnecting; +} + +void DB_SetHasMigrated(bool migrated) +{ + HasMigrated = migrated; +} + +void DB_SetIsConnecting(bool connecting) +{ + IsConnecting = connecting; +} + +bool DB_TryConnect() +{ + if (DB_IsConnected() || DB_IsConnecting()) + { + return false; + } + + DB_SetIsConnecting(true); + + if (SQL_CheckConfig("clientprefs")) + { + Database.Connect(OnDatabaseConnect, "clientprefs"); + return true; + } + + if (SQL_CheckConfig("storage-local")) + { + Database.Connect(OnDatabaseConnect, "storage-local"); + return true; + } + + SetFailState("Could not find any suitable database configs"); + return false; +} + +void DB_CreateTables() +{ + if (!DB_IsConnected()) + { + return; + } + + char driverId[64]; + g_Database.Driver.GetIdentifier(driverId, sizeof(driverId)); + + Transaction txn = new Transaction(); + + if (StrEqual(driverId, "mysql")) + { + txn.AddQuery( + "CREATE TABLE IF NOT EXISTS sm_cookies \ + ( \ + id INTEGER unsigned NOT NULL auto_increment, \ + name varchar(30) NOT NULL UNIQUE, \ + description varchar(255), \ + access INTEGER, \ + PRIMARY KEY (id) \ + )" + ); + + txn.AddQuery( + "CREATE TABLE IF NOT EXISTS sm_cookie_cache \ + ( \ + player varchar(65) NOT NULL, \ + cookie_id int(10) NOT NULL, \ + value varchar(100), \ + timestamp int NOT NULL, \ + PRIMARY KEY (player, cookie_id) \ + )" + ); + } + else if (StrEqual(driverId, "sqlite")) + { + txn.AddQuery( + "CREATE TABLE IF NOT EXISTS sm_cookies \ + ( \ + id INTEGER PRIMARY KEY AUTOINCREMENT, \ + name varchar(30) NOT NULL UNIQUE, \ + description varchar(255), \ + access INTEGER \ + )" + ); + + txn.AddQuery( + "CREATE TABLE IF NOT EXISTS sm_cookie_cache \ + ( \ + player varchar(65) NOT NULL, \ + cookie_id int(10) NOT NULL, \ + value varchar(100), \ + timestamp int, \ + PRIMARY KEY (player, cookie_id) \ + )" + ); + } + else if (StrEqual(driverId, "pgsql")) + { + txn.AddQuery( + "CREATE TABLE IF NOT EXISTS sm_cookies \ + ( \ + id serial, \ + name varchar(30) NOT NULL UNIQUE, \ + description varchar(255), \ + access INTEGER, \ + PRIMARY KEY (id) \ + )" + ); + + txn.AddQuery( + "CREATE TABLE IF NOT EXISTS sm_cookie_cache \ + ( \ + player varchar(65) NOT NULL, \ + cookie_id int NOT NULL, \ + value varchar(100), \ + timestamp int NOT NULL, \ + PRIMARY KEY (player, cookie_id) \ + )" + ); + + txn.AddQuery( + "CREATE OR REPLACE FUNCTION add_or_update_cookie(in_player VARCHAR(65), in_cookie INT, in_value VARCHAR(100), in_time INT) RETURNS VOID AS \ + $$ \ + BEGIN \ + LOOP \ + UPDATE sm_cookie_cache SET value = in_value, timestamp = in_time WHERE player = in_player AND cookie_id = in_cookie; \ + IF found THEN \ + RETURN; \ + END IF; \ + BEGIN \ + INSERT INTO sm_cookie_cache (player, cookie_id, value, timestamp) VALUES (in_player, in_cookie, in_value, in_time); \ + RETURN; \ + EXCEPTION WHEN unique_violation THEN \ + END; \ + END LOOP; \ + END; \ + $$ LANGUAGE plpgsql" + ); + } + else + { + ThrowError("Unsupported driver: %s", driverId); + delete txn; + return; + } + + g_Database.Execute(txn, OnTablesSuccess, OnTablesFailure); +} + +void DB_SelectCookieId(const char[] name) +{ + if (!DB_IsConnected()) + { + return; + } + + char query[2048]; + g_Database.Format(query, sizeof(query), + "SELECT id, name FROM sm_cookies WHERE name = '%s'", + name + ); + + g_Database.Query(OnSelectCookieId, query); +} + +void DB_SelectPlayerData(int client, const char[] authId) +{ + if (!DB_IsConnected()) + { + return; + } + + char query[2048]; + g_Database.Format(query, sizeof(query), + "SELECT sm_cookies.id, sm_cookies.name, sm_cookie_cache.value, sm_cookies.description, \ + sm_cookies.access, sm_cookie_cache.timestamp \ + FROM sm_cookies \ + JOIN sm_cookie_cache \ + ON sm_cookies.id = sm_cookie_cache.cookie_id \ + WHERE player = '%s'", + authId + ); + + g_Database.Query(OnSelectPlayerData, query, GetClientUserId(client)); +} + +void DB_InsertCookie(const char[] name, const char[] desc, CookieAccess accessLevel) +{ + if (!DB_IsConnected()) + { + return; + } + + char driverId[64]; + g_Database.Driver.GetIdentifier(driverId, sizeof(driverId)); + + char query[2048]; + + if (StrEqual(driverId, "mysql")) + { + g_Database.Format(query, sizeof(query), + "INSERT IGNORE INTO sm_cookies (name, description, access) \ + VALUES (\"%s\", \"%s\", %d)", + name, + desc, + accessLevel + ); + } + else if (StrEqual(driverId, "sqlite")) + { + g_Database.Format(query, sizeof(query), + "INSERT OR IGNORE INTO sm_cookies (name, description, access) \ + VALUES ('%s', '%s', %d)", + name, + desc, + accessLevel + ); + } + else if (StrEqual(driverId, "pgsql")) + { + g_Database.Format(query, sizeof(query), + "INSERT INTO sm_cookies (name, description, access) \ + VALUES ('%s', '%s', %d)", + name, + desc, + accessLevel + ); + } + else + { + ThrowError("Unsupported driver: %s", driverId); + return; + } + + DataPack dp = new DataPack(); + dp.WriteString(name); + + g_Database.Query(OnInsertCookie, query, dp); +} + +void DB_InsertPlayerData(const char[] authId, int cookieId, const char[] value) +{ + if (!DB_IsConnected()) + { + return; + } + + char driverId[64]; + g_Database.Driver.GetIdentifier(driverId, sizeof(driverId)); + + char query[2048]; + + int timestamp = GetTime(); + + if (StrEqual(driverId, "mysql")) + { + g_Database.Format(query, sizeof(query), + "INSERT INTO sm_cookie_cache (player, cookie_id, value, timestamp) \ + VALUES (\"%s\", %d, \"%s\", %d) \ + ON DUPLICATE KEY UPDATE \ + value = \"%s\", timestamp = %d", + authId, + cookieId, + value, + timestamp, + value, + timestamp + ); + } + else if (StrEqual(driverId, "sqlite")) + { + g_Database.Format(query, sizeof(query), + "INSERT OR REPLACE INTO sm_cookie_cache \ + (player, cookie_id, value, timestamp) \ + VALUES ('%s', %d, '%s', %d)", + authId, + cookieId, + value, + timestamp + ); + } + else if (StrEqual(driverId, "pgsql")) + { + /* + SourceMod comes with pgsql v9.6.9, UPSERT is in 9.5 + INSERT INTO sm_cookie_cache \ + (player, cookie_id, value, timestamp) \ + VALUES ('%s', %d, '%s', %d) + ON CONFLICT (player, cookie_id) DO UPDATE + SET value = '%s', timestamp = %d + */ + + g_Database.Format(query, sizeof(query), + "SELECT add_or_update_cookie ('%s', %d, '%s', %d)", + authId, + cookieId, + value, + timestamp + ); + } + else + { + ThrowError("Unsupported driver: %s", driverId); + return; + } + + g_Database.Query(OnInsertPlayerData, query); +} + +public void OnDatabaseConnect(Database db, const char[] error, any data) +{ + g_Database = db; + + DB_SetIsConnecting(false); + + if (!db || strlen(error) > 0) + { + LogError("Failed connecting to the database, error: %s", error); + return; + } + + if (!DB_HasMigrated()) + { + DB_CreateTables(); + } + else + { + InsertPendingCookies(); + } +} + +public void OnTablesSuccess(Database db, any data, int numQueries, Handle[] results, any[] queryData) +{ + DB_SetHasMigrated(true); + + LateLoadClients(); + InsertPendingCookies(); +} + +public void OnTablesFailure(Database db, any data, int numQueries, const char[] error, int failIndex, any[] queryData) +{ + PrintToServer("Failed creating tables, error: %s", error); +} + +public void OnSelectCookieId(Database db, DBResultSet results, const char[] error, any data) +{ + if (!db || strlen(error) > 0) + { + LogError("Failed selecting cookie id, error: %s", error); + return; + } + + if (!results.FetchRow()) + { + return; + } + + int id = results.FetchInt(0); + + char name[30]; + results.FetchString(1, name, sizeof(name)); + + SetCookieKnownDatabaseId(name, id); +} + +public void OnSelectPlayerData(Database db, DBResultSet results, const char[] error, int userId) +{ + if (!db || strlen(error) > 0) + { + LogError("Failed selecting player data, error: %s", error); + return; + } + + int client = GetClientOfUserId(userId); + if (client == 0) + { + return; + } + + SetPlayerDataPending(client, false); + + if (results == null) + { + return; + } + + while (results.FetchRow()) + { + char name[30]; + results.FetchString(1, name, sizeof(name)); + + CookieData cookieData; + cookieData.Name = name; + + bool hasData = GetCookieDataByName(name, cookieData); + if (!hasData) + { + cookieData.dbId = results.FetchInt(0); + cookieData.AccessLevel = view_as(results.FetchInt(4)); + + results.FetchString(3, cookieData.Description, sizeof(cookieData.Description)); + + SetCookieData(name, cookieData); + } + + PlayerData playerData; + playerData.Timestamp = results.FetchInt(5); + + results.FetchString(2, playerData.Value, sizeof(playerData.Value)); + + SetPlayerData(client, cookieData.Name, playerData); + } + + SetPlayerDataLoaded(client, true); + + Call_OnCookiesCached(client); + PrintToServer("Loaded data for %N", client); +} + +public void OnInsertCookie(Database db, DBResultSet results, const char[] error, DataPack dp) +{ + if (!db || strlen(error) > 0) + { + LogError("Failed inserting cookie, error: %s", error); + delete dp; + return; + } + + dp.Reset(); + + char name[30]; + dp.ReadString(name, sizeof(name)); + + delete dp; + + int dbId = results.InsertId; + if (dbId > 0) + { + SetCookieKnownDatabaseId(name, dbId); + return; + } + + // Manually lookup id if this was not an insert + DB_SelectCookieId(name); +} + +public void OnInsertPlayerData(Database db, DBResultSet results, const char[] error, any data) +{ + if (!db || strlen(error) > 0) + { + LogError("Failed inserting player data, error: %s", error); + return; + } +} diff --git a/plugins/clientprefs/forwards.sp b/plugins/clientprefs/forwards.sp new file mode 100644 index 0000000000..0ace6910c4 --- /dev/null +++ b/plugins/clientprefs/forwards.sp @@ -0,0 +1,13 @@ +static GlobalForward OnCookiesCached; + +void CreateForwards() +{ + OnCookiesCached = new GlobalForward("OnClientCookiesCached", ET_Ignore, Param_Cell); +} + +void Call_OnCookiesCached(int client) +{ + Call_StartForward(OnCookiesCached); + Call_PushCell(client); + Call_Finish(); +} diff --git a/plugins/clientprefs/menus.sp b/plugins/clientprefs/menus.sp new file mode 100644 index 0000000000..4f36b9bb07 --- /dev/null +++ b/plugins/clientprefs/menus.sp @@ -0,0 +1,202 @@ +enum struct CookieMenuData +{ + any UserData; + CookieMenu Type; + PrivateForward Handler; +} + +static Menu g_settingsMenu; +static StringMap g_menuData; + +void InitMenus() +{ + g_menuData = new StringMap(); + g_settingsMenu = new Menu(MenuHandler_Settings); +} + +bool GetMenuDataByName(const char[] name, CookieMenuData foundData) +{ + return g_menuData.GetArray(name, foundData, sizeof(foundData)); +} + +bool SetMenuDataByName(const char[] name, CookieMenuData data) +{ + return g_menuData.SetArray(name, data, sizeof(data)); +} + +void AddSettingsMenuItem( + Handle callingPlugin, + CookieData cookieData, + const char[] display, + CookieMenu type, + Function handler, + any userData +) { + CookieMenuData data; + + bool hasData = GetMenuDataByName(cookieData.Name, data); + if (!hasData) + { + data.Handler = new PrivateForward(ET_Ignore, Param_Cell, Param_Cell, Param_Cell, Param_String, Param_Cell); + g_settingsMenu.AddItem(cookieData.Name, display); + } + + if (handler != INVALID_FUNCTION) + { + data.Handler.AddFunction(callingPlugin, handler); + } + + data.Type = type; + data.UserData = userData; + + SetMenuDataByName(cookieData.Name, data); +} + +void DisplaySettingsMenu(int client) +{ + g_settingsMenu.SetTitle("%T:", "Client Settings", client); + g_settingsMenu.Display(client, MENU_TIME_FOREVER); +} + +void DisplayOptionSelectionMenu(int client, CookieData cookieData) +{ + CookieMenuData menuData; + + bool hasMenuData = GetMenuDataByName(cookieData.Name, menuData); + if (!hasMenuData) + { + return; + } + + Menu menu = new Menu(MenuHandler_Option, MENU_ACTIONS_DEFAULT | MenuAction_DisplayItem); + menu.SetTitle("%T:", "Choose Option", client); + + // Store cookie name in menu item 0 for context + menu.AddItem(cookieData.Name, "", ITEMDRAW_IGNORE); + + switch (menuData.Type) + { + case CookieMenu_YesNo: + { + menu.AddItem("yes", "Yes"); + menu.AddItem("no", "No"); + } + case CookieMenu_YesNo_Int: + { + menu.AddItem("1", "Yes"); + menu.AddItem("0", "No"); + } + case CookieMenu_OnOff: + { + menu.AddItem("on", "On"); + menu.AddItem("off", "Off"); + } + case CookieMenu_OnOff_Int: + { + menu.AddItem("1", "On"); + menu.AddItem("0", "Off"); + } + } + + menu.Display(client, MENU_TIME_FOREVER); +} + +public int MenuHandler_Settings(Menu menu, MenuAction action, int param1, int param2) +{ + if (action == MenuAction_Select) + { + char name[30]; + menu.GetItem(param2, name, sizeof(name)); + + CookieData cookieData; + + bool hasCookieData = GetCookieDataByName(name, cookieData); + if (!hasCookieData) + { + return 0; + } + + CookieMenuData menuData; + + bool hasMenuData = GetMenuDataByName(name, menuData); + if (!hasMenuData) + { + return 0; + } + + if (menuData.Handler != null) + { + Call_StartForward(menuData.Handler); + Call_PushCell(param1); + Call_PushCell(CookieMenuAction_SelectOption); + Call_PushCell(menuData.UserData); + Call_PushString(""); + Call_PushCell(0); + Call_Finish(); + } + + DisplayOptionSelectionMenu(param1, cookieData); + } + + return 0; +} + +public int MenuHandler_Option(Menu menu, MenuAction action, int param1, int param2) +{ + if (action == MenuAction_Select) + { + char name[30]; + menu.GetItem(0, name, sizeof(name)); + + char value[100]; + menu.GetItem(param2, value, sizeof(value)); + + CookieData cookieData; + + bool hasCookieData = GetCookieDataByName(name, cookieData); + if (!hasCookieData) + { + return 0; + } + + bool updated = UpdatePlayerCookieValue(param1, name, value); + if (!updated) + { + return 0; + } + + PrintToChat(param1, "[SM] %t", "Cookie Changed Value", name, value); + } + else if (action == MenuAction_DisplayItem) + { + char name[30]; + menu.GetItem(0, name, sizeof(name)); + + CookieMenuData data; + + bool hasData = GetMenuDataByName(name, data); + if (!hasData || data.Handler == null) + { + return 0; + } + + char buffer[100]; + menu.GetItem(param2, "", 0, _, buffer, sizeof(buffer)); + + Call_StartForward(data.Handler); + Call_PushCell(param1); + Call_PushCell(CookieMenuAction_DisplayOption); + Call_PushCell(data.UserData); + Call_PushStringEx(buffer, sizeof(buffer), SM_PARAM_STRING_COPY, SM_PARAM_COPYBACK); + Call_PushCell(sizeof(buffer)); + Call_Finish(); + + return RedrawMenuItem(buffer); + } + else if (action == MenuAction_End) + { + delete menu; + } + + return 0; +} \ No newline at end of file diff --git a/plugins/clientprefs/natives.sp b/plugins/clientprefs/natives.sp new file mode 100644 index 0000000000..d7518b43e1 --- /dev/null +++ b/plugins/clientprefs/natives.sp @@ -0,0 +1,283 @@ +void CreateNatives() +{ + CreateNative("RegClientCookie", Native_RegCookie); + CreateNative("FindClientCookie", Native_FindCookie); + CreateNative("SetClientCookie", Native_SetCookieValue_Old); + CreateNative("GetClientCookie", Native_GetCookieValue_Old); + CreateNative("GetCookieAccess", Native_GetCookieAccess); + CreateNative("GetClientCookieTime", Native_GetClientCookieTime_Old); + CreateNative("SetAuthIdCookie", Native_SetCookieValueByAuthId_Old); + CreateNative("AreClientCookiesCached", Native_AreClientCookiesCached); + CreateNative("SetCookiePrefabMenu", Native_SetCookiePrefabMenu); + //CreateNative("SetCookieMenuItem", Native_SetCookieMenuItem); + CreateNative("ShowCookieMenu", Native_ShowCookieMenu); + CreateNative("GetCookieIterator", Native_GetCookieIterator); + CreateNative("ReadCookieIterator", Native_ReadCookieIterator); + + CreateNative("Cookie.Cookie", Native_RegCookie); + CreateNative("Cookie.Find", Native_FindCookie); + CreateNative("Cookie.Set", Native_SetCookieValue); + CreateNative("Cookie.Get", Native_GetCookieValue); + CreateNative("Cookie.AccessLevel.get", Native_GetCookieAccess); + CreateNative("Cookie.GetClientTime", Native_GetClientCookieTime); + CreateNative("Cookie.SetPrefabMenu", Native_SetCookiePrefabMenu); + CreateNative("Cookie.SetByAuthId", Native_SetCookieValueByAuthId); +} + +public any Native_RegCookie(Handle plugin, int numParams) +{ + char name[30]; + GetNativeString(1, name, sizeof(name)); + + char description[255]; + GetNativeString(2, description, sizeof(description)); + + CookieAccess accessLevel = GetNativeCell(3); + + CookieData cookieData; + + bool found = GetCookieDataByName(name, cookieData); + if (!found) + { + cookieData.Name = name; + cookieData.Description = description; + cookieData.AccessLevel = accessLevel; + + SetCookieData(name, cookieData); + DB_InsertCookie(name, description, accessLevel); + } + + return CreateConsumerHandleForCookieData(cookieData, plugin); +} + +public any Native_FindCookie(Handle plugin, int numParams) +{ + char name[30]; + GetNativeString(1, name, sizeof(name)); + + CookieData cookieData; + + bool found = GetCookieDataByName(name, cookieData); + if (!found) + { + return INVALID_HANDLE; + } + + return CreateConsumerHandleForCookieData(cookieData, plugin); +} + +public any Native_SetCookieValue(Handle plugin, int numParams) +{ + any handle = GetNativeCell(1); + int client = GetNativeCell(2); + + char value[100]; + GetNativeString(3, value, sizeof(value)); + + return SetCookieValue_Impl(client, value, handle); +} + +public any Native_SetCookieValue_Old(Handle plugin, int numParams) +{ + int client = GetNativeCell(1); + any handle = GetNativeCell(2); + + char value[100]; + GetNativeString(3, value, sizeof(value)); + + return SetCookieValue_Impl(client, value, handle); +} + +public any Native_GetCookieValue(Handle plugin, int numParams) +{ + any handle = GetNativeCell(1); + int client = GetNativeCell(2); + + return GetCookieValue_Impl(client, handle); +} + +public any Native_GetCookieValue_Old(Handle plugin, int numParams) +{ + int client = GetNativeCell(1); + any handle = GetNativeCell(2); + + return GetCookieValue_Impl(client, handle); +} + +public any Native_GetCookieAccess(Handle plugin, int numParams) +{ + any handle = GetNativeCell(1); + + CookieData data; + + bool hasData = GetCookieDataFromConsumerHandle(handle, data); + if (!hasData) + { + // TODO: Throw? + return -1; + } + + return data.AccessLevel; +} + +public any Native_GetClientCookieTime(Handle plugin, int numParams) +{ + any handle = GetNativeCell(1); + int client = GetNativeCell(2); + + return GetClientCookieTime_Impl(client, handle); +} + +public any Native_GetClientCookieTime_Old(Handle plugin, int numParams) +{ + int client = GetNativeCell(1); + any handle = GetNativeCell(2); + + return GetClientCookieTime_Impl(client, handle); +} + +public any Native_AreClientCookiesCached(Handle plugin, int numParams) +{ + int client = GetNativeCell(1); + if (client < 1 || client > MaxClients) + { + ThrowNativeError(SP_ERROR_NATIVE, "Client index %d is invalid", client); + return false; + } + + return IsPlayerDataCached(client); +} + +public any Native_SetCookiePrefabMenu(Handle plugin, int numParams) +{ + any handle = GetNativeCell(1); + + CookieData data; + + bool hasData = GetCookieDataFromConsumerHandle(handle, data); + if (!hasData) + { + // TODO: Throw? + return false; + } + + CookieMenu type = GetNativeCell(2); + + char display[128]; + GetNativeString(3, display, sizeof(display)); + + Function handler = GetNativeFunction(4); + + any userData = GetNativeCell(5); + + AddSettingsMenuItem(plugin, data, display, type, handler, userData); + return true; +} + +public any Native_SetCookieValueByAuthId(Handle plugin, int numParams) +{ + any handle = GetNativeCell(1); + + char authId[32]; + GetNativeString(2, authId, sizeof(authId)); + + char value[100]; + GetNativeString(3, value, sizeof(value)); + + return SetCookieValueByAuthId_Impl(authId, value, handle); +} + +public any Native_SetCookieValueByAuthId_Old(Handle plugin, int numParams) +{ + char authId[32]; + GetNativeString(1, authId, sizeof(authId)); + + any handle = GetNativeCell(2); + + char value[100]; + GetNativeString(3, value, sizeof(value)); + + return SetCookieValueByAuthId_Impl(authId, value, handle); +} + +public any Native_ShowCookieMenu(Handle plugin, int numParams) +{ + int client = GetNativeCell(1); + return DisplaySettingsMenu(client); +} + +public any Native_GetCookieIterator(Handle plugin, int numParams) +{ + return CreateConsumerHandleForIterator(plugin); +} + +public any Native_ReadCookieIterator(Handle plugin, int numParams) +{ + any handle = GetNativeCell(1); + + int index = GetIteratorIndexFromConsumerHandle(handle); + if (index < 0 || index >= GetCookieCount()) + { + return false; + } + + CookieData data; + GetCookieDataByIndex(index, data); + + SetNativeString(2, data.Name, GetNativeCell(3)); + + SetNativeCellRef(4, data.AccessLevel); + + SetNativeString(5, data.Description, GetNativeCell(6)); + + IncrementIteratorIndexForConsumerHandle(handle); + return true; +} + +any SetCookieValue_Impl(int client, const char value[100], any handle) +{ + CookieData cookieData; + GetCookieDataFromConsumerHandle(handle, cookieData); + + return UpdatePlayerCookieValue(client, cookieData.Name, value); +} + +any GetCookieValue_Impl(int client, any handle) +{ + PlayerData data; + + bool hasData = GetCookiePlayerDataFromConsumerHandle(handle, client, data); + if (!hasData) + { + return false; + } + + int maxlength = GetNativeCell(4); + + SetNativeString(3, data.Value, maxlength); + return true; +} + +any GetClientCookieTime_Impl(int client, any handle) +{ + PlayerData data; + + bool hasData = GetCookiePlayerDataFromConsumerHandle(handle, client, data); + if (!hasData) + { + return -1; + } + + return data.Timestamp; +} + +any SetCookieValueByAuthId_Impl(const char[] authId, const char value[100], any handle) +{ + int foundClient = FindClientByAuthId(authId); + if (foundClient == -1) + { + return false; + } + + return SetCookieValue_Impl(foundClient, value, handle); +} diff --git a/plugins/clientprefs/utils.sp b/plugins/clientprefs/utils.sp new file mode 100644 index 0000000000..3079ea882e --- /dev/null +++ b/plugins/clientprefs/utils.sp @@ -0,0 +1,23 @@ +int FindClientByAuthId(const char[] authId) +{ + for (int i = 1; i <= MaxClients; i++) + { + if (!IsFakeClient(i) && IsClientConnected(i)) + { + char targetAuthId[32]; + + bool gotAuth = GetClientAuthId(i, AuthId_Steam2, targetAuthId, sizeof(targetAuthId)); + if (!gotAuth) + { + continue; + } + + if (StrEqual(targetAuthId, authId)) + { + return i; + } + } + } + + return -1; +} diff --git a/plugins/include/clientprefs.inc b/plugins/include/clientprefs.inc index 6ab4e203c4..84fb40802f 100644 --- a/plugins/include/clientprefs.inc +++ b/plugins/include/clientprefs.inc @@ -75,6 +75,7 @@ enum CookieMenuAction }; #define COOKIE_MAX_NAME_LENGTH 30 /**< Maximum Cookie name length. */ +#define COOKIE_MAX_VALUE_LENGTH 100 /**< Maximum Cookie value length. */ #define COOKIE_MAX_DESCRIPTION_LENGTH 255 /**< Maximum Cookie description length. */ /** @@ -388,24 +389,19 @@ native int GetClientCookieTime(int client, Handle cookie); /** * Do not edit below this line! */ -public Extension __ext_cprefs = +public SharedPlugin __pl_cprefs = { name = "Client Preferences", - file = "clientprefs.ext", -#if defined AUTOLOAD_EXTENSIONS - autoload = 1, -#else - autoload = 0, -#endif -#if defined REQUIRE_EXTENSIONS + file = "clientprefs.smx", +#if defined REQUIRE_PLUGIN required = 1, #else required = 0, #endif }; -#if !defined REQUIRE_EXTENSIONS -public void __ext_cprefs_SetNTVOptional() +#if !defined REQUIRE_PLUGIN +public void __pl_cprefs_SetNTVOptional() { MarkNativeAsOptional("RegClientCookie"); MarkNativeAsOptional("FindClientCookie");