3 * =============================================================================
4 * SourceMod Client Preferences Extension
5 * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
6 * =============================================================================
8 * This program is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU General Public License, version 3.0, as published by the
10 * Free Software Foundation.
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
17 * You should have received a copy of the GNU General Public License along with
18 * this program. If not, see <http://www.gnu.org/licenses/>.
20 * As a special exception, AlliedModders LLC gives you permission to link the
21 * code of this program (as well as its derivative works) to "Half-Life 2," the
22 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
23 * by the Valve Corporation. You must obey the GNU General Public License in
24 * all respects for all other code used. Additionally, AlliedModders LLC grants
25 * this exception to all derivative works. AlliedModders LLC defines further
26 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
27 * or <http://www.sourcemod.net/license.php>.
32 #include "extension.h"
36 cell_t RegClientPrefCookie(IPluginContext *pContext, const cell_t *params)
38 if (g_ClientPrefs.Database == NULL && !g_ClientPrefs.databaseLoading)
40 return pContext->ThrowNativeError("Clientprefs is disabled due to a failed database connection");
44 pContext->LocalToString(params[1], &name);
48 return pContext->ThrowNativeError("Cannot create preference cookie with no name");
52 pContext->LocalToString(params[2], &desc);
54 Cookie *pCookie = g_CookieManager.CreateCookie(name, desc, (CookieAccess)params[3]);
61 return handlesys->CreateHandle(g_CookieType,
63 pContext->GetIdentity(),
64 myself->GetIdentity(),
68 cell_t FindClientPrefCookie(IPluginContext *pContext, const cell_t *params)
70 if (g_ClientPrefs.Database == NULL && !g_ClientPrefs.databaseLoading)
72 return pContext->ThrowNativeError("Clientprefs is disabled due to a failed database connection");
76 pContext->LocalToString(params[1], &name);
78 Cookie *pCookie = g_CookieManager.FindCookie(name);
85 return handlesys->CreateHandle(g_CookieType,
87 pContext->GetIdentity(),
88 myself->GetIdentity(),
92 cell_t SetAuthIdCookie(IPluginContext *pContext, const cell_t *params)
94 if (g_ClientPrefs.Database == NULL && !g_ClientPrefs.databaseLoading)
96 return pContext->ThrowNativeError("Clientprefs is disabled due to a failed database connection");
100 pContext->LocalToString(params[1], &steamID);
102 // convert cookie handle to Cookie*
103 Handle_t hndl = static_cast<Handle_t>(params[2]);
108 sec.pIdentity = myself->GetIdentity();
112 if ((err = handlesys->ReadHandle(hndl, g_CookieType, &sec, (void **)&pCookie))
115 return pContext->ThrowNativeError("Invalid Cookie handle %x (error %d)", hndl, err);
118 int i_dbId = pCookie->dbid;
120 pContext->LocalToString(params[3], &value);
122 // make sure the steamID isn't currently connected
123 if (int client = IsAuthIdConnected(steamID))
125 // use regular code for connected players
126 return g_CookieManager.SetCookieValue(pCookie, client, value);
129 // constructor calls strncpy for us
130 CookieData *payload = new CookieData(value);
132 // set changed so players connecting later in during the same map will have the correct value
133 payload->changed = true;
134 payload->timestamp = time(NULL);
136 // edit database table
137 TQueryOp *op = new TQueryOp(Query_InsertData, pCookie);
138 // limit player auth length which doubles for cookie name length
139 strncpy(op->m_params.steamId, steamID, MAX_NAME_LENGTH);
140 op->m_params.steamId[MAX_NAME_LENGTH-1] = '\0';
141 op->m_params.cookieId = i_dbId;
142 op->m_params.data = payload;
144 g_ClientPrefs.AddQueryToQueue(op);
149 cell_t SetClientPrefCookie(IPluginContext *pContext, const cell_t *params)
151 if (g_ClientPrefs.Database == NULL && !g_ClientPrefs.databaseLoading)
153 return pContext->ThrowNativeError("Clientprefs is disabled due to a failed database connection");
156 int client = params[1];
158 if ((client < 1) || (client > playerhelpers->GetMaxClients()))
160 return pContext->ThrowNativeError("Client index %d is invalid", client);
163 Handle_t hndl = static_cast<Handle_t>(params[2]);
168 sec.pIdentity = myself->GetIdentity();
172 if ((err = handlesys->ReadHandle(hndl, g_CookieType, &sec, (void **)&pCookie))
175 return pContext->ThrowNativeError("Invalid Cookie handle %x (error %d)", hndl, err);
179 pContext->LocalToString(params[3], &value);
181 return g_CookieManager.SetCookieValue(pCookie, client, value);
184 cell_t GetClientPrefCookie(IPluginContext *pContext, const cell_t *params)
186 if (g_ClientPrefs.Database == NULL && !g_ClientPrefs.databaseLoading)
188 return pContext->ThrowNativeError("Clientprefs is disabled due to a failed database connection");
191 int client = params[1];
193 if ((client < 1) || (client > playerhelpers->GetMaxClients()))
195 return pContext->ThrowNativeError("Client index %d is invalid", client);
198 Handle_t hndl = static_cast<Handle_t>(params[2]);
203 sec.pIdentity = myself->GetIdentity();
207 if ((err = handlesys->ReadHandle(hndl, g_CookieType, &sec, (void **)&pCookie))
210 return pContext->ThrowNativeError("Invalid Cookie handle %x (error %d)", hndl, err);
215 g_CookieManager.GetCookieValue(pCookie, client, &value);
217 pContext->StringToLocal(params[3], params[4], value);
222 cell_t AreClientCookiesCached(IPluginContext *pContext, const cell_t *params)
224 if (g_ClientPrefs.Database == NULL && !g_ClientPrefs.databaseLoading)
226 return pContext->ThrowNativeError("Clientprefs is disabled due to a failed database connection");
229 int client = params[1];
231 if ((client < 1) || (client > playerhelpers->GetMaxClients()))
233 return pContext->ThrowNativeError("Client index %d is invalid", client);
236 return g_CookieManager.AreClientCookiesCached(client);
239 cell_t GetCookieAccess(IPluginContext *pContext, const cell_t *params)
241 if (g_ClientPrefs.Database == NULL && !g_ClientPrefs.databaseLoading)
243 return pContext->ThrowNativeError("Clientprefs is disabled due to a failed database connection");
246 Handle_t hndl = static_cast<Handle_t>(params[1]);
251 sec.pIdentity = myself->GetIdentity();
255 if ((err = handlesys->ReadHandle(hndl, g_CookieType, &sec, (void **)&pCookie))
258 return pContext->ThrowNativeError("Invalid Cookie handle %x (error %d)", hndl, err);
261 return pCookie->access;
264 static cell_t GetCookieIterator(IPluginContext *pContext, const cell_t *params)
266 if (g_ClientPrefs.Database == NULL && !g_ClientPrefs.databaseLoading)
268 return pContext->ThrowNativeError("Clientprefs is disabled due to a failed database connection");
271 SourceHook::List<Cookie *>::iterator *iter = new SourceHook::List<Cookie *>::iterator;
272 *iter = g_CookieManager.cookieList.begin();
274 Handle_t hndl = handlesys->CreateHandle(g_CookieIterator, iter, pContext->GetIdentity(), myself->GetIdentity(), NULL);
275 if (hndl == BAD_HANDLE)
283 static cell_t ReadCookieIterator(IPluginContext *pContext, const cell_t *params)
285 if (g_ClientPrefs.Database == NULL && !g_ClientPrefs.databaseLoading)
287 return pContext->ThrowNativeError("Clientprefs is disabled due to a failed database connection");
290 SourceHook::List<Cookie *>::iterator *iter;
292 Handle_t hndl = static_cast<Handle_t>(params[1]);
297 sec.pIdentity = myself->GetIdentity();
299 if ((err = handlesys->ReadHandle(hndl, g_CookieIterator, &sec, (void **)&iter))
302 return pContext->ThrowNativeError("Invalid Cookie iterator handle %x (error %d)", hndl, err);
305 if (*iter == g_CookieManager.cookieList.end())
310 Cookie *pCookie = (Cookie *)**iter;
314 pContext->StringToLocalUTF8(params[2], params[3], pCookie->name, NULL);
315 pContext->StringToLocalUTF8(params[5], params[6], pCookie->description, NULL);
318 pContext->LocalToPhysAddr(params[4], &addr);
319 *addr = pCookie->access;
324 cell_t ShowSettingsMenu(IPluginContext *pContext, const cell_t *params)
326 if (g_ClientPrefs.Database == NULL && !g_ClientPrefs.databaseLoading)
328 return pContext->ThrowNativeError("Clientprefs is disabled due to a failed database connection");
332 Translate(message, sizeof(message), "%T:", 2, NULL, "Client Settings", ¶ms[1]);
334 g_CookieManager.clientMenu->SetDefaultTitle(message);
335 g_CookieManager.clientMenu->Display(params[1], 0, NULL);
340 cell_t AddSettingsMenuItem(IPluginContext *pContext, const cell_t *params)
342 if (g_ClientPrefs.Database == NULL && !g_ClientPrefs.databaseLoading)
344 return pContext->ThrowNativeError("Clientprefs is disabled due to a failed database connection");
348 pContext->LocalToString(params[3], &display);
350 /* Register a callback */
351 ItemHandler *pItem = new ItemHandler;
352 pItem->isAutoMenu = false;
353 pItem->forward = forwards->CreateForwardEx(NULL, ET_Ignore, 5, NULL, Param_Cell, Param_Cell, Param_Cell, Param_String, Param_Cell);
355 pItem->forward->AddFunction(pContext, static_cast<funcid_t>(params[1]));
358 AutoMenuData *data = new AutoMenuData;
359 data->datavalue = params[2];
360 data->handler = pItem;
361 UTIL_Format(info, sizeof(info), "%x", data);
363 ItemDrawInfo draw(display, 0);
365 g_CookieManager.clientMenu->AppendItem(info, draw);
367 /* Track this in case the plugin unloads */
369 IPlugin *pPlugin = plsys->FindPluginByContext(pContext->GetContext());
370 SourceHook::List<char *> *pList = NULL;
372 if (!pPlugin->GetProperty("SettingsMenuItems", (void **)&pList, false) || !pList)
374 pList = new SourceHook::List<char *>;
375 pPlugin->SetProperty("SettingsMenuItems", pList);
378 char *copyarray = new char[strlen(display)+1];
379 UTIL_Format(copyarray, strlen(display)+1, "%s", display);
381 pList->push_back(copyarray);
386 cell_t AddSettingsPrefabMenuItem(IPluginContext *pContext, const cell_t *params)
388 if (g_ClientPrefs.Database == NULL && !g_ClientPrefs.databaseLoading)
390 return pContext->ThrowNativeError("Clientprefs is disabled due to a failed database connection");
393 Handle_t hndl = static_cast<Handle_t>(params[1]);
398 sec.pIdentity = myself->GetIdentity();
402 if ((err = handlesys->ReadHandle(hndl, g_CookieType, &sec, (void **)&pCookie))
405 return pContext->ThrowNativeError("Invalid Cookie handle %x (error %d)", hndl, err);
408 /* Register a callback */
409 ItemHandler *pItem = new ItemHandler;
410 pItem->isAutoMenu = true;
411 pItem->autoMenuType = (CookieMenu)params[2];
414 /* User passed a function id for a callback */
417 pItem->forward = forwards->CreateForwardEx(NULL, ET_Ignore, 5, NULL, Param_Cell, Param_Cell, Param_Cell, Param_String, Param_Cell);
418 pItem->forward->AddFunction(pContext, static_cast<funcid_t>(params[4]));
422 pItem->forward = NULL;
426 pContext->LocalToString(params[3], &display);
428 ItemDrawInfo draw(display, 0);
431 AutoMenuData *data = new AutoMenuData;
432 data->datavalue = params[5];
433 data->pCookie = pCookie;
434 data->type = (CookieMenu)params[2];
435 data->handler = pItem;
436 UTIL_Format(info, sizeof(info), "%x", data);
438 g_CookieManager.clientMenu->AppendItem(info, draw);
440 /* Track this in case the plugin unloads */
442 IPlugin *pPlugin = plsys->FindPluginByContext(pContext->GetContext());
443 SourceHook::List<char *> *pList = NULL;
445 if (!pPlugin->GetProperty("SettingsMenuItems", (void **)&pList, false) || !pList)
447 pList = new SourceHook::List<char *>;
448 pPlugin->SetProperty("SettingsMenuItems", pList);
451 char *copyarray = new char[strlen(display)+1];
452 UTIL_Format(copyarray, strlen(display)+1, "%s", display);
454 pList->push_back(copyarray);
459 cell_t GetClientCookieTime(IPluginContext *pContext, const cell_t *params)
461 if (g_ClientPrefs.Database == NULL && !g_ClientPrefs.databaseLoading)
463 return pContext->ThrowNativeError("Clientprefs is disabled due to a failed database connection");
466 Handle_t hndl = static_cast<Handle_t>(params[2]);
471 sec.pIdentity = myself->GetIdentity();
475 if ((err = handlesys->ReadHandle(hndl, g_CookieType, &sec, (void **)&pCookie))
478 return pContext->ThrowNativeError("Invalid Cookie handle %x (error %d)", hndl, err);
483 if (!g_CookieManager.GetCookieTime(pCookie, params[1], &value))
491 sp_nativeinfo_t g_ClientPrefNatives[] =
493 {"RegClientCookie", RegClientPrefCookie},
494 {"FindClientCookie", FindClientPrefCookie},
495 {"SetClientCookie", SetClientPrefCookie},
496 {"SetAuthIdCookie", SetAuthIdCookie},
497 {"GetClientCookie", GetClientPrefCookie},
498 {"AreClientCookiesCached", AreClientCookiesCached},
499 {"GetCookieAccess", GetCookieAccess},
500 {"ReadCookieIterator", ReadCookieIterator},
501 {"GetCookieIterator", GetCookieIterator},
502 {"ShowCookieMenu", ShowSettingsMenu},
503 {"SetCookieMenuItem", AddSettingsMenuItem},
504 {"SetCookiePrefabMenu", AddSettingsPrefabMenuItem},
505 {"GetClientCookieTime", GetClientCookieTime},