extensions/clientprefs/extension.cpp
author David Anderson <dvander@alliedmods.net>
Wed Oct 15 01:01:36 2008 -0700 (2008-10-15)
changeset 2359 a51e376f3700
parent 2338 b9a152a270c9
child 2373 01dd8a057823
permissions -rw-r--r--
Various clientprefs logging to try and catch bug 2698 in the act.
pred@2009
     1
/**
pred@2009
     2
 * vim: set ts=4 :
pred@2009
     3
 * =============================================================================
pred@2009
     4
 * SourceMod Client Preferences Extension
pred@2009
     5
 * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
pred@2009
     6
 * =============================================================================
pred@2009
     7
 *
pred@2009
     8
 * This program is free software; you can redistribute it and/or modify it under
pred@2009
     9
 * the terms of the GNU General Public License, version 3.0, as published by the
pred@2009
    10
 * Free Software Foundation.
pred@2009
    11
 * 
pred@2009
    12
 * This program is distributed in the hope that it will be useful, but WITHOUT
pred@2009
    13
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
pred@2009
    14
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
pred@2009
    15
 * details.
pred@2009
    16
 *
pred@2009
    17
 * You should have received a copy of the GNU General Public License along with
pred@2009
    18
 * this program.  If not, see <http://www.gnu.org/licenses/>.
pred@2009
    19
 *
pred@2009
    20
 * As a special exception, AlliedModders LLC gives you permission to link the
pred@2009
    21
 * code of this program (as well as its derivative works) to "Half-Life 2," the
pred@2009
    22
 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
pred@2009
    23
 * by the Valve Corporation.  You must obey the GNU General Public License in
pred@2009
    24
 * all respects for all other code used.  Additionally, AlliedModders LLC grants
pred@2009
    25
 * this exception to all derivative works.  AlliedModders LLC defines further
pred@2009
    26
 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
pred@2009
    27
 * or <http://www.sourcemod.net/license.php>.
pred@2009
    28
 *
pred@2009
    29
 * Version: $Id$
pred@2009
    30
 */
pred@2009
    31
pred@2009
    32
#include "extension.h"
pred@2009
    33
pred@2009
    34
/**
pred@2009
    35
 * @file extension.cpp
pred@2009
    36
 * @brief Implement extension code here.
pred@2009
    37
 */
pred@2009
    38
pred@2009
    39
ClientPrefs g_ClientPrefs;		/**< Global singleton for extension's main interface */
pred@2009
    40
pred@2009
    41
SMEXT_LINK(&g_ClientPrefs);
pred@2009
    42
pred@2009
    43
HandleType_t g_CookieType = 0;
pred@2009
    44
CookieTypeHandler g_CookieTypeHandler;
pred@2009
    45
pred@2048
    46
HandleType_t g_CookieIterator = 0;
pred@2048
    47
CookieIteratorHandler g_CookieIteratorHandler;
pred@2048
    48
pred@2009
    49
pred@2009
    50
int driver = 0;
pred@2009
    51
pred@2009
    52
bool ClientPrefs::SDK_OnLoad(char *error, size_t maxlength, bool late)
pred@2207
    53
{
pred@2207
    54
	queryMutex = threader->MakeMutex();
pred@2207
    55
	cookieMutex = threader->MakeMutex();
pred@2207
    56
pred@2207
    57
	DBInfo = dbi->FindDatabaseConf("clientprefs");
pred@2009
    58
pred@2009
    59
	if (DBInfo == NULL)
pred@2009
    60
	{
pred@2009
    61
		DBInfo = dbi->FindDatabaseConf("default");
pred@2009
    62
pred@2009
    63
		if (DBInfo == NULL)
pred@2009
    64
		{
pred@2009
    65
			snprintf(error, maxlength, "Could not find \"clientprefs\" or \"default\" database configs");
pred@2009
    66
			return false;
pred@2009
    67
		}
pred@2009
    68
	}
pred@2009
    69
pred@2009
    70
	if (DBInfo->driver[0] != '\0')
pred@2009
    71
	{
pred@2009
    72
		Driver = dbi->FindOrLoadDriver(DBInfo->driver);
pred@2009
    73
	}
pred@2009
    74
	else
pred@2009
    75
	{
pred@2009
    76
		Driver = dbi->GetDefaultDriver();
pred@2009
    77
	}
pred@2009
    78
pred@2009
    79
	if (Driver == NULL)
pred@2009
    80
	{
pred@2009
    81
		snprintf(error, maxlength, "Could not load DB Driver \"%s\"", DBInfo->driver);
pred@2009
    82
		return false;
pred@2009
    83
	}
pred@2009
    84
pred@2207
    85
	Database = NULL;
pred@2207
    86
	databaseLoading = true;
pred@2207
    87
	TQueryOp *op = new TQueryOp(Query_Connect, 0);
pred@2207
    88
	dbi->AddToThreadQueue(op, PrioQueue_High);
pred@2009
    89
dvander@2135
    90
	dbi->AddDependency(myself, Driver);
dvander@2135
    91
pred@2009
    92
	sharesys->AddNatives(myself, g_ClientPrefNatives);
pred@2009
    93
	sharesys->RegisterLibrary(myself, "clientprefs");
pred@2048
    94
	g_CookieManager.cookieDataLoadedForward = forwards->CreateForward("OnClientCookiesCached", ET_Ignore, 1, NULL, Param_Cell);
pred@2009
    95
pred@2009
    96
	g_CookieType = handlesys->CreateType("Cookie", 
pred@2009
    97
		&g_CookieTypeHandler, 
pred@2009
    98
		0, 
pred@2009
    99
		NULL, 
pred@2009
   100
		NULL, 
pred@2009
   101
		myself->GetIdentity(), 
pred@2009
   102
		NULL);
pred@2009
   103
pred@2048
   104
	g_CookieIterator = handlesys->CreateType("CookieIterator", 
pred@2048
   105
		&g_CookieIteratorHandler, 
pred@2048
   106
		0, 
pred@2048
   107
		NULL, 
pred@2048
   108
		NULL, 
pred@2048
   109
		myself->GetIdentity(), 
pred@2048
   110
		NULL);
pred@2048
   111
pred@2048
   112
	IMenuStyle *style = menus->GetDefaultStyle();
pred@2048
   113
	g_CookieManager.clientMenu = style->CreateMenu(&g_Handler, NULL);
pred@2048
   114
	g_CookieManager.clientMenu->SetDefaultTitle("Client Settings:");
pred@2048
   115
pred@2048
   116
	plsys->AddPluginsListener(&g_CookieManager);
pred@2048
   117
pred@2048
   118
	phrases = translator->CreatePhraseCollection();
pred@2048
   119
	phrases->AddPhraseFile("clientprefs.phrases");
pred@2048
   120
	phrases->AddPhraseFile("common.phrases");
pred@2048
   121
pred@2009
   122
	return true;
pred@2009
   123
}
pred@2009
   124
pred@2009
   125
void ClientPrefs::SDK_OnAllLoaded()
pred@2009
   126
{
pred@2009
   127
	playerhelpers->AddClientListener(&g_CookieManager);
pred@2009
   128
}
pred@2009
   129
dvander@2135
   130
bool ClientPrefs::QueryInterfaceDrop(SMInterface *pInterface)
dvander@2135
   131
{
dvander@2135
   132
	if ((void *)pInterface == (void *)(Database->GetDriver()))
dvander@2135
   133
	{
dvander@2135
   134
		return false;
dvander@2135
   135
	}
dvander@2135
   136
dvander@2135
   137
	return true;
dvander@2135
   138
}
dvander@2135
   139
dvander@2135
   140
void ClientPrefs::NotifyInterfaceDrop(SMInterface *pInterface)
dvander@2135
   141
{
dvander@2135
   142
	if (Database != NULL && (void *)pInterface == (void *)(Database->GetDriver()))
dvander@2135
   143
	{
pred@2207
   144
		InsertCookieQuery->Destroy();
pred@2207
   145
		SelectDataQuery->Destroy();
pred@2207
   146
		SelectIdQuery->Destroy();
pred@2207
   147
		InsertDataQuery->Destroy();
pred@2207
   148
pred@2207
   149
		InsertCookieQuery = NULL;
pred@2207
   150
		SelectDataQuery = NULL;
pred@2207
   151
		SelectIdQuery = NULL;
pred@2207
   152
		InsertDataQuery = NULL;
pred@2207
   153
dvander@2135
   154
		Database->Close();
dvander@2135
   155
		Database = NULL;
dvander@2135
   156
	}
dvander@2135
   157
}
dvander@2135
   158
pred@2009
   159
void ClientPrefs::SDK_OnUnload()
pred@2009
   160
{
pred@2009
   161
	handlesys->RemoveType(g_CookieType, myself->GetIdentity());
pred@2131
   162
	handlesys->RemoveType(g_CookieIterator, myself->GetIdentity());
pred@2009
   163
pred@2009
   164
	g_CookieManager.Unload();
pred@2009
   165
dvander@2135
   166
	if (Database != NULL)
dvander@2135
   167
	{
dvander@2135
   168
		Database->Close();
dvander@2135
   169
	}
pred@2009
   170
pred@2048
   171
	forwards->ReleaseForward(g_CookieManager.cookieDataLoadedForward);
pred@2048
   172
pred@2048
   173
	g_CookieManager.clientMenu->Destroy();
pred@2131
   174
pred@2131
   175
	phrases->Destroy();
pred@2131
   176
pred@2131
   177
	plsys->RemovePluginsListener(&g_CookieManager);
pred@2131
   178
	playerhelpers->RemoveClientListener(&g_CookieManager);
pred@2207
   179
pred@2207
   180
	/* Kill all our prepared queries - Queries are guaranteed to be flushed before this is called */
pred@2207
   181
pred@2207
   182
	if (InsertCookieQuery != NULL)
pred@2207
   183
	{
pred@2207
   184
		InsertCookieQuery->Destroy();
pred@2207
   185
	}
pred@2207
   186
pred@2207
   187
	if (SelectDataQuery != NULL)
pred@2207
   188
	{
pred@2207
   189
		SelectDataQuery->Destroy();
pred@2207
   190
	}
pred@2207
   191
pred@2207
   192
	if (SelectIdQuery != NULL)
pred@2207
   193
	{
pred@2207
   194
		SelectIdQuery->Destroy();
pred@2207
   195
	}
pred@2207
   196
pred@2207
   197
	if (InsertDataQuery != NULL)
pred@2207
   198
	{
pred@2207
   199
		InsertDataQuery->Destroy();
pred@2207
   200
	}
pred@2207
   201
pred@2207
   202
	queryMutex->DestroyThis();
pred@2207
   203
	cookieMutex->DestroyThis();
pred@2207
   204
}
pred@2207
   205
pred@2207
   206
void ClientPrefs::DatabaseConnect()
pred@2207
   207
{
pred@2207
   208
	char error[256];
pred@2207
   209
	int errCode = 0;
pred@2207
   210
pred@2207
   211
	Database = Driver->Connect(DBInfo, true, error, sizeof(error));
pred@2207
   212
pred@2207
   213
	if (Database == NULL)
pred@2207
   214
	{
pred@2207
   215
		g_pSM->LogError(myself, error);
pred@2207
   216
		databaseLoading = false;
pred@2207
   217
		ProcessQueryCache();
pred@2207
   218
		return;
pred@2207
   219
	}
pred@2207
   220
pred@2207
   221
	const char *identifier = Driver->GetIdentifier();
pred@2207
   222
pred@2207
   223
	if (strcmp(identifier, "sqlite") == 0)
pred@2207
   224
	{
pred@2207
   225
		driver = DRIVER_SQLITE;
pred@2207
   226
dvander@2338
   227
		if (!Database->DoSimpleQuery(
pred@2207
   228
				"CREATE TABLE IF NOT EXISTS sm_cookies  \
pred@2207
   229
				( \
pred@2207
   230
					id INTEGER PRIMARY KEY AUTOINCREMENT, \
pred@2207
   231
					name varchar(30) NOT NULL UNIQUE, \
pred@2207
   232
					description varchar(255), \
pred@2207
   233
					access INTEGER \
dvander@2338
   234
				)"))
pred@2220
   235
		{
dvander@2338
   236
			g_pSM->LogMessage(myself, "Failed to CreateTable sm_cookies: %s", Database->GetError());
dvander@2338
   237
			goto fatal_fail;
pred@2220
   238
		}
pred@2220
   239
dvander@2338
   240
		if (!Database->DoSimpleQuery(
pred@2207
   241
				"CREATE TABLE IF NOT EXISTS sm_cookie_cache \
pred@2207
   242
				( \
pred@2207
   243
					player varchar(65) NOT NULL, \
pred@2207
   244
					cookie_id int(10) NOT NULL, \
pred@2207
   245
					value varchar(100), \
pred@2207
   246
					timestamp int, \
pred@2207
   247
					PRIMARY KEY (player, cookie_id) \
dvander@2338
   248
				)"))
pred@2220
   249
		{
dvander@2338
   250
			g_pSM->LogMessage(myself, "Failed to CreateTable sm_cookie_cache: %s", Database->GetError());
dvander@2338
   251
			goto fatal_fail;
pred@2220
   252
		}
pred@2207
   253
	}
pred@2207
   254
	else if (strcmp(identifier, "mysql") == 0)
pred@2207
   255
	{
pred@2207
   256
		driver = DRIVER_MYSQL;
pred@2207
   257
dvander@2338
   258
		if (!Database->DoSimpleQuery(
pred@2207
   259
				"CREATE TABLE IF NOT EXISTS sm_cookies \
pred@2207
   260
				( \
pred@2207
   261
					id INTEGER unsigned NOT NULL auto_increment, \
pred@2207
   262
					name varchar(30) NOT NULL UNIQUE, \
pred@2207
   263
					description varchar(255), \
pred@2207
   264
					access INTEGER, \
pred@2207
   265
					PRIMARY KEY (id) \
dvander@2338
   266
				)"))
pred@2220
   267
		{
dvander@2338
   268
			g_pSM->LogMessage(myself, "Failed to CreateTable sm_cookies: %s", Database->GetError());
dvander@2338
   269
			goto fatal_fail;
pred@2220
   270
		}
pred@2220
   271
dvander@2338
   272
		if (!Database->DoSimpleQuery(
pred@2207
   273
				"CREATE TABLE IF NOT EXISTS sm_cookie_cache \
pred@2207
   274
				( \
pred@2207
   275
					player varchar(65) NOT NULL, \
pred@2207
   276
					cookie_id int(10) NOT NULL, \
pred@2207
   277
					value varchar(100), \
pred@2207
   278
					timestamp int NOT NULL, \
pred@2207
   279
					PRIMARY KEY (player, cookie_id) \
dvander@2338
   280
				)"))
pred@2220
   281
		{
dvander@2338
   282
			g_pSM->LogMessage(myself, "Failed to CreateTable sm_cookie_cache: %s", Database->GetError());
dvander@2338
   283
			goto fatal_fail;
pred@2220
   284
		}
pred@2207
   285
	}
pred@2207
   286
	else
pred@2207
   287
	{
pred@2207
   288
		g_pSM->LogError(myself, "Unsupported driver \"%s\"", identifier);
dvander@2338
   289
		goto fatal_fail;
pred@2207
   290
	}
pred@2207
   291
pred@2207
   292
	if (driver == DRIVER_MYSQL)
pred@2207
   293
	{
pred@2207
   294
		InsertCookieQuery = Database->PrepareQuery(
pred@2207
   295
				"INSERT IGNORE INTO sm_cookies(name, description, access) \
pred@2207
   296
				VALUES(?, ?, ?)",
pred@2207
   297
				error, sizeof(error), &errCode);
pred@2220
   298
pred@2220
   299
		if (InsertCookieQuery == NULL)
pred@2220
   300
		{
pred@2220
   301
			g_pSM->LogMessage(myself, "Failed to prepare query InsertCookie: %s (%i)", error, errCode);
dvander@2338
   302
			goto fatal_fail;
pred@2220
   303
		}
pred@2220
   304
pred@2207
   305
		InsertDataQuery = Database->PrepareQuery(
pred@2207
   306
				"INSERT INTO sm_cookie_cache(player, cookie_id, value, timestamp) \
pred@2207
   307
				VALUES(?, ?, ?, ?) \
pred@2207
   308
				ON DUPLICATE KEY UPDATE value = ?, timestamp = ?",
pred@2207
   309
				error, sizeof(error), &errCode);
pred@2220
   310
pred@2220
   311
		if (InsertDataQuery == NULL)
pred@2220
   312
		{
pred@2220
   313
			g_pSM->LogMessage(myself, "Failed to prepare query InsertData: %s (%i)", error, errCode);
dvander@2338
   314
			goto fatal_fail;
pred@2220
   315
		}
pred@2207
   316
	}
pred@2207
   317
	else
pred@2207
   318
	{
pred@2207
   319
		InsertCookieQuery = Database->PrepareQuery(
pred@2207
   320
				"INSERT OR IGNORE INTO sm_cookies(name, description, access) \
pred@2207
   321
				VALUES(?, ?, ?)", 
pred@2207
   322
				error, sizeof(error), &errCode);
pred@2220
   323
pred@2220
   324
		if (InsertCookieQuery == NULL)
pred@2220
   325
		{
pred@2220
   326
			g_pSM->LogMessage(myself, "Failed to prepare query InsertCookie: %s (%i)", error, errCode);
dvander@2338
   327
			goto fatal_fail;
pred@2220
   328
		}
pred@2220
   329
pred@2207
   330
		InsertDataQuery = Database->PrepareQuery(
pred@2207
   331
				"INSERT OR REPLACE INTO sm_cookie_cache(player, cookie_id, value, timestamp) \
pred@2207
   332
				VALUES(?, ?, ?, ?)", 
pred@2207
   333
				error, sizeof(error), &errCode);
pred@2220
   334
pred@2220
   335
		if (InsertDataQuery == NULL)
pred@2220
   336
		{
pred@2220
   337
			g_pSM->LogMessage(myself, "Failed to prepare query InsertData: %s (%i)", error, errCode);
dvander@2338
   338
			goto fatal_fail;
pred@2220
   339
		}
pred@2207
   340
	}
pred@2207
   341
pred@2207
   342
	SelectDataQuery = Database->PrepareQuery(
pred@2207
   343
			"SELECT sm_cookies.name, sm_cookie_cache.value, sm_cookies.description, sm_cookies.access \
pred@2207
   344
			FROM sm_cookies \
pred@2207
   345
			JOIN sm_cookie_cache \
pred@2207
   346
			ON sm_cookies.id = sm_cookie_cache.cookie_id \
pred@2207
   347
			WHERE player = ?",
pred@2207
   348
			error, sizeof(error), &errCode);
pred@2207
   349
pred@2220
   350
	if (SelectDataQuery == NULL)
pred@2220
   351
	{
pred@2220
   352
		g_pSM->LogMessage(myself, "Failed to prepare query SelectData: %s (%i)", error, errCode);
dvander@2338
   353
		goto fatal_fail;
pred@2220
   354
	}
pred@2220
   355
pred@2207
   356
	SelectIdQuery = Database->PrepareQuery(
pred@2207
   357
			"SELECT id \
pred@2207
   358
			FROM sm_cookies \
pred@2207
   359
			WHERE name=?",
pred@2207
   360
			error, sizeof(error), &errCode);
pred@2207
   361
pred@2220
   362
	if (SelectIdQuery == NULL)
pred@2220
   363
	{
pred@2220
   364
		g_pSM->LogMessage(myself, "Failed to prepare query SelectId: %s (%i)", error, errCode);
dvander@2338
   365
		goto fatal_fail;
pred@2220
   366
	}
pred@2220
   367
pred@2207
   368
	databaseLoading = false;
pred@2207
   369
pred@2207
   370
	ProcessQueryCache();
pred@2207
   371
pred@2207
   372
	return;
dvander@2338
   373
dvander@2338
   374
fatal_fail:
dvander@2338
   375
	if (SelectIdQuery != NULL)
dvander@2338
   376
	{
dvander@2338
   377
		SelectIdQuery->Destroy();
dvander@2338
   378
		SelectIdQuery = NULL;
dvander@2338
   379
	}
dvander@2338
   380
	if (SelectDataQuery != NULL)
dvander@2338
   381
	{
dvander@2338
   382
		SelectDataQuery->Destroy();
dvander@2338
   383
		SelectDataQuery = NULL;
dvander@2338
   384
	}
dvander@2338
   385
	if (InsertCookieQuery != NULL)
dvander@2338
   386
	{
dvander@2338
   387
		InsertCookieQuery->Destroy();
dvander@2338
   388
		InsertCookieQuery = NULL;
dvander@2338
   389
	}
dvander@2338
   390
	if (InsertDataQuery != NULL)
dvander@2338
   391
	{
dvander@2338
   392
		InsertDataQuery->Destroy();
dvander@2338
   393
		InsertDataQuery = NULL;
dvander@2338
   394
	}
dvander@2338
   395
	Database->Close();
dvander@2338
   396
	Database = NULL;
dvander@2338
   397
	databaseLoading = false;
dvander@2338
   398
	ProcessQueryCache();
pred@2207
   399
}
pred@2207
   400
pred@2207
   401
bool ClientPrefs::AddQueryToQueue( TQueryOp *query )
pred@2207
   402
{
pred@2207
   403
	queryMutex->Lock();
pred@2207
   404
pred@2207
   405
	if (Database == NULL && databaseLoading)
pred@2207
   406
	{
pred@2207
   407
		cachedQueries.push_back(query);
pred@2207
   408
		queryMutex->Unlock();
pred@2207
   409
		return true;
pred@2207
   410
	}
pred@2207
   411
pred@2207
   412
	queryMutex->Unlock();
pred@2207
   413
pred@2207
   414
	if (Database)
pred@2207
   415
	{
pred@2207
   416
		query->SetDatabase(Database);
pred@2207
   417
		query->SetPreparedQuery();
dvander@2359
   418
		if (query->GetQuery() == NULL && query->GetType() != Query_Connect)
dvander@2359
   419
		{
dvander@2359
   420
			g_pSM->LogError(myself, "Invalid aqtq query %d being inserted! glorp: %p, %p",
dvander@2359
   421
				query->GetType(),
dvander@2359
   422
				query->GetDriver(),
dvander@2359
   423
				query);
dvander@2359
   424
			query->Destroy();
dvander@2359
   425
		}
dvander@2359
   426
		else
dvander@2359
   427
		{
dvander@2359
   428
			dbi->AddToThreadQueue(query, PrioQueue_Normal);
dvander@2359
   429
		}
pred@2207
   430
		return true;
pred@2207
   431
	}
pred@2207
   432
pred@2220
   433
	query->Destroy();
pred@2220
   434
pred@2207
   435
	/* If Database is NULL and we're not in the loading phase it must have failed - Can't do much */
pred@2207
   436
	return false;
pred@2207
   437
}
pred@2207
   438
pred@2207
   439
void ClientPrefs::ProcessQueryCache()
pred@2207
   440
{
pred@2207
   441
	SourceHook::List<TQueryOp *>::iterator iter;
pred@2207
   442
pred@2207
   443
	queryMutex->Lock();
pred@2207
   444
pred@2207
   445
	iter = cachedQueries.begin();
pred@2207
   446
	
pred@2207
   447
	while (iter != cachedQueries.end())
pred@2207
   448
	{
dvander@2359
   449
		TQueryOp *op = *iter;
pred@2207
   450
pred@2207
   451
		if (Database != NULL)
pred@2207
   452
		{
pred@2207
   453
			op->SetDatabase(Database);
pred@2207
   454
			op->SetPreparedQuery();
dvander@2359
   455
			if (op->GetQuery() == NULL && op->GetType() != Query_Connect)
dvander@2359
   456
			{
dvander@2359
   457
				g_pSM->LogError(myself, "Invalid pqc query %d being inserted! glorp: %p, %p",
dvander@2359
   458
					op->GetType(),
dvander@2359
   459
					op->GetDriver(),
dvander@2359
   460
					op);
dvander@2359
   461
				op->Destroy();
dvander@2359
   462
			}
dvander@2359
   463
			else
dvander@2359
   464
			{
dvander@2359
   465
				dbi->AddToThreadQueue(op, PrioQueue_Normal);
dvander@2359
   466
			}
pred@2207
   467
		}
pred@2207
   468
		else
pred@2207
   469
		{
dvander@2359
   470
			op->Destroy();
pred@2207
   471
		}
pred@2207
   472
pred@2207
   473
		iter++;
pred@2207
   474
	}
pred@2207
   475
pred@2207
   476
	cachedQueries.clear();
pred@2207
   477
pred@2207
   478
	queryMutex->Unlock();
pred@2048
   479
}
pred@2048
   480
pred@2048
   481
size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...)
pred@2048
   482
{
pred@2048
   483
	va_list ap;
pred@2048
   484
	va_start(ap, fmt);
pred@2048
   485
	size_t len = vsnprintf(buffer, maxlength, fmt, ap);
pred@2048
   486
	va_end(ap);
pred@2048
   487
pred@2048
   488
	if (len >= maxlength)
pred@2048
   489
	{
pred@2048
   490
		buffer[maxlength - 1] = '\0';
pred@2048
   491
		return (maxlength - 1);
pred@2048
   492
	}
pred@2048
   493
	else
pred@2048
   494
	{
pred@2048
   495
		return len;
pred@2048
   496
	}
pred@2048
   497
}
pred@2048
   498
pred@2048
   499
bool Translate(char *buffer, 
pred@2048
   500
				   size_t maxlength,
pred@2048
   501
				   const char *format,
pred@2048
   502
				   unsigned int numparams,
pred@2048
   503
				   size_t *pOutLength,
pred@2048
   504
				   ...)
pred@2048
   505
{
pred@2048
   506
	va_list ap;
pred@2048
   507
	unsigned int i;
pred@2048
   508
	const char *fail_phrase;
pred@2048
   509
	void *params[MAX_TRANSLATE_PARAMS];
pred@2048
   510
pred@2048
   511
	if (numparams > MAX_TRANSLATE_PARAMS)
pred@2048
   512
	{
pred@2048
   513
		assert(false);
pred@2048
   514
		return false;
pred@2048
   515
	}
pred@2048
   516
pred@2048
   517
	va_start(ap, pOutLength);
pred@2048
   518
	for (i = 0; i < numparams; i++)
pred@2048
   519
	{
pred@2048
   520
		params[i] = va_arg(ap, void *);
pred@2048
   521
	}
pred@2048
   522
	va_end(ap);
pred@2048
   523
pred@2048
   524
	if (!g_ClientPrefs.phrases->FormatString(buffer,
pred@2048
   525
		maxlength, 
pred@2048
   526
		format, 
pred@2048
   527
		params,
pred@2048
   528
		numparams,
pred@2048
   529
		pOutLength,
pred@2048
   530
		&fail_phrase))
pred@2048
   531
	{
pred@2048
   532
		if (fail_phrase != NULL)
pred@2048
   533
		{
pred@2048
   534
			g_pSM->LogError(myself, "[SM] Could not find core phrase: %s", fail_phrase);
pred@2048
   535
		}
pred@2048
   536
		else
pred@2048
   537
		{
pred@2048
   538
			g_pSM->LogError(myself, "[SM] Unknown fatal error while translating a core phrase.");
pred@2048
   539
		}
pred@2048
   540
pred@2048
   541
		return false;
pred@2048
   542
	}
pred@2048
   543
pred@2048
   544
	return true;
pred@2009
   545
}
pred@2009
   546
pred@2009
   547
pred@2048
   548