Added automatic database migrations and revamped overall database structure.

Now I can push database migrations without making the plugin's users do the querying on their own.

List of migrations:
* **Converted all SteamIDs in the database from SteamID3 to Steam Account ID format. The difference is simply stripping of the [U:1: prefix and ] suffix. This change speeds up the queries and reduces the database's size by a lot.**
* Removal of `workshop/` paths from all map names in the database.
* Added index to `lastlogin` to speedup the filtering I added to rankings with `shavit_rankings_llrecalc`.
* Removed `country` from database. It was completely unnecessary.
* Converted IP addresses from plaintext to a single 4 bytes integer.
* Converted `date` of records from a string to integer.
This commit is contained in:
shavit 2019-05-12 07:57:04 +03:00
parent dc11301325
commit 547f90ef62
8 changed files with 494 additions and 214 deletions

View File

@ -74,6 +74,21 @@ enum
CPR_NotOnGround = (1 << 3)
};
enum
{
Migration_RemoveWorkshopMaptiers,
Migration_RemoveWorkshopMapzones,
Migration_RemoveWorkshopPlayertimes,
Migration_LastLoginIndex,
Migration_RemoveCountry,
Migration_ConvertIPAddresses,
Migration_ConvertSteamIDsUsers,
Migration_ConvertSteamIDsPlayertimes,
Migration_ConvertSteamIDsChat,
Migration_PlayertimesDateToInt,
MIGRATIONS_END
};
enum
{
Zone_Start,
@ -259,6 +274,25 @@ stock bool IsSource2013(EngineVersion ev)
return (ev == Engine_CSS || ev == Engine_TF2);
}
stock void IPAddressToString(int ip, char[] buffer, int maxlen)
{
FormatEx(buffer, maxlen, "%d.%d.%d.%d", ((ip >> 24) & 0xFF), ((ip >> 16) & 0xFF), ((ip >> 8) & 0xFF), (ip & 0xFF));
}
stock int IPStringToAddress(const char[] ip)
{
char sExplodedAddress[4][4];
ExplodeString(ip, ".", sExplodedAddress, 4, 4, false);
int iIPAddress =
(StringToInt(sExplodedAddress[0]) << 24) |
(StringToInt(sExplodedAddress[1]) << 16) |
(StringToInt(sExplodedAddress[2]) << 8) |
StringToInt(sExplodedAddress[3]);
return iIPAddress;
}
// time formatting!
stock void FormatSeconds(float time, char[] newtime, int newtimesize, bool precise = true)
{
@ -1132,10 +1166,10 @@ native int Shavit_ForceHUDUpdate(int client, bool spectators);
* Opens the stats menu for a client.
*
* @param client Client index.
* @param authid Target SteamID3 to use.
* @param steamid Target Steam account ID to use.
* @noreturn
*/
native void Shavit_OpenStatsMenu(int client, const char[] authid);
native void Shavit_OpenStatsMenu(int client, int steamid);
/**
* Retrieves the amount of #1 records a player has.

View File

@ -1344,14 +1344,14 @@ void SQL_DBConnect()
if(bMySQL)
{
FormatEx(sQuery, 512,
"CREATE TABLE IF NOT EXISTS `%schat` (`auth` VARCHAR(32) NOT NULL, `name` INT NOT NULL DEFAULT 0, `ccname` VARCHAR(128) COLLATE 'utf8mb4_unicode_ci', `message` INT NOT NULL DEFAULT 0, `ccmessage` VARCHAR(16) COLLATE 'utf8mb4_unicode_ci', PRIMARY KEY (`auth`), CONSTRAINT `%sch_auth` FOREIGN KEY (`auth`) REFERENCES `%susers` (`auth`) ON UPDATE CASCADE ON DELETE CASCADE) ENGINE=INNODB;",
"CREATE TABLE IF NOT EXISTS `%schat` (`auth` INT NOT NULL, `name` INT NOT NULL DEFAULT 0, `ccname` VARCHAR(128) COLLATE 'utf8mb4_unicode_ci', `message` INT NOT NULL DEFAULT 0, `ccmessage` VARCHAR(16) COLLATE 'utf8mb4_unicode_ci', PRIMARY KEY (`auth`), CONSTRAINT `%sch_auth` FOREIGN KEY (`auth`) REFERENCES `%susers` (`auth`) ON UPDATE CASCADE ON DELETE CASCADE) ENGINE=INNODB;",
gS_MySQLPrefix, gS_MySQLPrefix, gS_MySQLPrefix);
}
else
{
FormatEx(sQuery, 512,
"CREATE TABLE IF NOT EXISTS `%schat` (`auth` VARCHAR(32) NOT NULL, `name` INT NOT NULL DEFAULT 0, `ccname` VARCHAR(128), `message` INT NOT NULL DEFAULT 0, `ccmessage` VARCHAR(16), PRIMARY KEY (`auth`), CONSTRAINT `%sch_auth` FOREIGN KEY (`auth`) REFERENCES `%susers` (`auth`) ON UPDATE CASCADE ON DELETE CASCADE);",
"CREATE TABLE IF NOT EXISTS `%schat` (`auth` INT NOT NULL, `name` INT NOT NULL DEFAULT 0, `ccname` VARCHAR(128), `message` INT NOT NULL DEFAULT 0, `ccmessage` VARCHAR(16), PRIMARY KEY (`auth`), CONSTRAINT `%sch_auth` FOREIGN KEY (`auth`) REFERENCES `%susers` (`auth`) ON UPDATE CASCADE ON DELETE CASCADE);",
gS_MySQLPrefix, gS_MySQLPrefix, gS_MySQLPrefix);
}
@ -1389,7 +1389,9 @@ void SaveToDatabase(int client)
return;
}
if(!GetClientAuthId(client, AuthId_Steam3, sAuthID3, 32))
int iSteamID = GetSteamAccountID(client);
if(iSteamID == 0)
{
return;
}
@ -1404,8 +1406,8 @@ void SaveToDatabase(int client)
char sQuery[512];
FormatEx(sQuery, 512,
"REPLACE INTO %schat (auth, name, ccname, message, ccmessage) VALUES ('%s', %d, '%s', %d, '%s');",
gS_MySQLPrefix, sAuthID3, gB_NameEnabled[client], sEscapedName, gB_MessageEnabled[client], sEscapedMessage);
"REPLACE INTO %schat (auth, name, ccname, message, ccmessage) VALUES (%d, %d, '%s', %d, '%s');",
gS_MySQLPrefix, iSteamID, gB_NameEnabled[client], sEscapedName, gB_MessageEnabled[client], sEscapedMessage);
gH_SQL.Query(SQL_UpdateUser_Callback, sQuery, 0, DBPrio_Low);
}
@ -1427,15 +1429,15 @@ void LoadFromDatabase(int client)
return;
}
char sAuthID3[32];
int iSteamID = GetSteamAccountID(client);
if(!GetClientAuthId(client, AuthId_Steam3, sAuthID3, 32))
if(iSteamID == 0)
{
return;
}
char sQuery[256];
FormatEx(sQuery, 256, "SELECT name, ccname, message, ccmessage FROM %schat WHERE auth = '%s';", gS_MySQLPrefix, sAuthID3);
FormatEx(sQuery, 256, "SELECT name, ccname, message, ccmessage FROM %schat WHERE auth = %d;", gS_MySQLPrefix, iSteamID);
gH_SQL.Query(SQL_GetChat_Callback, sQuery, GetClientSerial(client), DBPrio_Low);
}

View File

@ -711,16 +711,23 @@ public Action Command_WipePlayer(int client, int args)
void DeleteUserData(int client, const char[] sAuthID3)
{
char sAuthID[32];
strcopy(sAuthID, 32, sAuthID3);
ReplaceString(sAuthID, 32, "[U:1:", "");
ReplaceString(sAuthID, 32, "]", "");
int iSteamID = StringToInt(sAuthID);
if(gB_Replay)
{
char sQueryGetWorldRecords[256];
FormatEx(sQueryGetWorldRecords, 256,
"SELECT map, id, style, track FROM %splayertimes WHERE auth = '%s';",
gS_MySQLPrefix, sAuthID3);
"SELECT map, id, style, track FROM %splayertimes WHERE auth = %d;",
gS_MySQLPrefix, iSteamID);
DataPack hPack = new DataPack();
hPack.WriteCell(client);
hPack.WriteString(sAuthID3);
hPack.WriteCell(iSteamID);
gH_SQL.Query(SQL_DeleteUserData_GetRecords_Callback, sQueryGetWorldRecords, hPack, DBPrio_High);
}
@ -729,14 +736,14 @@ void DeleteUserData(int client, const char[] sAuthID3)
{
char sQueryDeleteUserTimes[256];
FormatEx(sQueryDeleteUserTimes, 256,
"DELETE FROM %splayertimes WHERE auth = '%s';",
gS_MySQLPrefix, sAuthID3);
"DELETE FROM %splayertimes WHERE auth = %d;",
gS_MySQLPrefix, iSteamID);
DataPack steamPack = new DataPack();
steamPack.WriteString(sAuthID3);
steamPack.WriteCell(client);
DataPack hSteamPack = new DataPack();
hSteamPack.WriteCell(iSteamID);
hSteamPack.WriteCell(client);
gH_SQL.Query(SQL_DeleteUserTimes_Callback, sQueryDeleteUserTimes, steamPack, DBPrio_High);
gH_SQL.Query(SQL_DeleteUserTimes_Callback, sQueryDeleteUserTimes, hSteamPack, DBPrio_High);
}
}
@ -745,9 +752,7 @@ public void SQL_DeleteUserData_GetRecords_Callback(Database db, DBResultSet resu
DataPack hPack = view_as<DataPack>(data);
hPack.Reset();
int client = hPack.ReadCell();
char sAuthID3[32];
hPack.ReadString(sAuthID3, 32);
int iSteamID = hPack.ReadCell();
delete hPack;
if(results == null)
@ -782,19 +787,18 @@ public void SQL_DeleteUserData_GetRecords_Callback(Database db, DBResultSet resu
hTransaction.AddQuery(sQueryGetWorldRecordID, hTransPack);
}
DataPack steamPack = new DataPack();
steamPack.WriteString(sAuthID3);
steamPack.WriteCell(client);
DataPack hSteamPack = new DataPack();
hSteamPack.WriteCell(iSteamID);
hSteamPack.WriteCell(client);
gH_SQL.Execute(hTransaction, Trans_OnRecordCompare, INVALID_FUNCTION, steamPack, DBPrio_High);
gH_SQL.Execute(hTransaction, Trans_OnRecordCompare, INVALID_FUNCTION, hSteamPack, DBPrio_High);
}
public void Trans_OnRecordCompare(Database db, any data, int numQueries, DBResultSet[] results, any[] queryData)
{
DataPack pack = view_as<DataPack>(data);
pack.Reset();
char sAuthID3[32];
pack.ReadString(sAuthID3, 32);
DataPack hPack = view_as<DataPack>(data);
hPack.Reset();
int iSteamID = hPack.ReadCell();
for(int i = 0; i < numQueries; i++)
{
@ -821,55 +825,53 @@ public void Trans_OnRecordCompare(Database db, any data, int numQueries, DBResul
char sQueryDeleteUserTimes[256];
FormatEx(sQueryDeleteUserTimes, 256,
"DELETE FROM %splayertimes WHERE auth = '%s';",
gS_MySQLPrefix, sAuthID3);
"DELETE FROM %splayertimes WHERE auth = %d;",
gS_MySQLPrefix, iSteamID);
gH_SQL.Query(SQL_DeleteUserTimes_Callback, sQueryDeleteUserTimes, pack, DBPrio_High);
gH_SQL.Query(SQL_DeleteUserTimes_Callback, sQueryDeleteUserTimes, hPack, DBPrio_High);
}
public void SQL_DeleteUserTimes_Callback(Database db, DBResultSet results, const char[] error, any data)
{
DataPack pack = view_as<DataPack>(data);
pack.Reset();
char sAuthID3[32];
pack.ReadString(sAuthID3, 32);
DataPack hPack = view_as<DataPack>(data);
hPack.Reset();
int iSteamID = hPack.ReadCell();
if(results == null)
{
LogError("Timer error! Failed to wipe user data (wipe | delete user times). Reason: %s", error);
delete pack;
delete hPack;
return;
}
char sQueryDeleteUsers[256];
FormatEx(sQueryDeleteUsers, 256, "DELETE FROM %susers WHERE auth = '%s';",
gS_MySQLPrefix, sAuthID3);
FormatEx(sQueryDeleteUsers, 256, "DELETE FROM %susers WHERE auth = %d;",
gS_MySQLPrefix, iSteamID);
gH_SQL.Query(SQL_DeleteUserData_Callback, sQueryDeleteUsers, pack, DBPrio_High);
gH_SQL.Query(SQL_DeleteUserData_Callback, sQueryDeleteUsers, hPack, DBPrio_High);
}
public void SQL_DeleteUserData_Callback(Database db, DBResultSet results, const char[] error, any data)
{
DataPack pack = view_as<DataPack>(data);
pack.Reset();
char sAuthID3[32];
pack.ReadString(sAuthID3, 32);
int client = pack.ReadCell();
delete pack;
DataPack hPack = view_as<DataPack>(data);
hPack.Reset();
int iSteamID = hPack.ReadCell();
int client = hPack.ReadCell();
delete hPack;
if(results == null)
{
LogError("Timer error! Failed to wipe user data (wipe | delete user data, id %s). Reason: %s", error, sAuthID3);
LogError("Timer error! Failed to wipe user data (wipe | delete user data, id [U:1:%d]). Reason: %s", error, iSteamID);
return;
}
Shavit_ReloadLeaderboards();
Shavit_PrintToChat(client, "Finished wiping timer data for user %s%s%s.",
gS_ChatStrings.sVariable, sAuthID3, gS_ChatStrings.sText);
Shavit_PrintToChat(client, "Finished wiping timer data for user %s[U:1:%d]%s.",
gS_ChatStrings.sVariable, iSteamID, gS_ChatStrings.sText);
}
public Action Command_AutoBhop(int client, int args)
@ -1870,9 +1872,9 @@ public void OnClientPutInServer(int client)
SDKHook(client, SDKHook_PreThinkPost, PreThinkPost);
char sAuthID3[32];
int iSteamID = GetSteamAccountID(client);
if(!GetClientAuthId(client, AuthId_Steam3, sAuthID3, 32))
if(iSteamID == 0)
{
KickClient(client, "%T", "VerificationFailed", client);
@ -1887,15 +1889,9 @@ public void OnClientPutInServer(int client)
char[] sEscapedName = new char[iLength];
gH_SQL.Escape(sName, sEscapedName, iLength);
char sIP[64];
GetClientIP(client, sIP, 64);
char sCountry[128];
if(!GeoipCountry(sIP, sCountry, 128))
{
strcopy(sCountry, 128, "Local Area Network");
}
char sIPAddress[64];
GetClientIP(client, sIPAddress, 64);
int iIPAddress = IPStringToAddress(sIPAddress);
int iTime = GetTime();
@ -1903,12 +1899,16 @@ public void OnClientPutInServer(int client)
if(gB_MySQL)
{
FormatEx(sQuery, 512, "INSERT INTO %susers (auth, name, country, ip, lastlogin) VALUES ('%s', '%s', '%s', '%s', %d) ON DUPLICATE KEY UPDATE name = '%s', country = '%s', ip = '%s', lastlogin = %d;", gS_MySQLPrefix, sAuthID3, sEscapedName, sCountry, sIP, iTime, sEscapedName, sCountry, sIP, iTime);
FormatEx(sQuery, 512,
"INSERT INTO %susers (auth, name, ip, lastlogin) VALUES (%d, '%s', %d, %d) ON DUPLICATE KEY UPDATE name = '%s', ip = %d, lastlogin = %d;",
gS_MySQLPrefix, iSteamID, sEscapedName, iIPAddress, iTime, sEscapedName, iIPAddress, iTime);
}
else
{
FormatEx(sQuery, 512, "REPLACE INTO %susers (auth, name, country, ip, lastlogin) VALUES ('%s', '%s', '%s', '%s', %d);", gS_MySQLPrefix, sAuthID3, sEscapedName, sCountry, sIP, iTime);
FormatEx(sQuery, 512,
"REPLACE INTO %susers (auth, name, ip, lastlogin) VALUES (%d, '%s', %d, %d);",
gS_MySQLPrefix, iSteamID, sEscapedName, iIPAddress, iTime);
}
gH_SQL.Query(SQL_InsertUser_Callback, sQuery, GetClientSerial(client));
@ -2212,30 +2212,210 @@ void SQL_DBConnect()
gH_SQL.Driver.GetIdentifier(sDriver, 8);
gB_MySQL = StrEqual(sDriver, "mysql", false);
char sQuery[512];
// migrations will only exist for mysql. sorry sqlite users
if(gB_MySQL)
{
FormatEx(sQuery, 512, "CREATE TABLE IF NOT EXISTS `%susers` (`auth` VARCHAR(32) NOT NULL, `name` VARCHAR(32) COLLATE 'utf8mb4_general_ci', `country` VARCHAR(32), `ip` VARCHAR(64), `lastlogin` INT NOT NULL DEFAULT -1, `points` FLOAT NOT NULL DEFAULT 0, PRIMARY KEY (`auth`), INDEX `points` (`points`)) ENGINE=INNODB;", gS_MySQLPrefix);
char sQuery[128];
FormatEx(sQuery, 128, "CREATE TABLE IF NOT EXISTS `%smigrations` (`code` TINYINT NOT NULL, UNIQUE INDEX `code` (`code`));", gS_MySQLPrefix);
gH_SQL.Query(SQL_CreateMigrationsTable_Callback, sQuery, 0, DBPrio_High);
}
else
{
FormatEx(sQuery, 512, "CREATE TABLE IF NOT EXISTS `%susers` (`auth` VARCHAR(32) NOT NULL PRIMARY KEY, `name` VARCHAR(32), `country` VARCHAR(32), `ip` VARCHAR(64), `lastlogin` INTEGER NOT NULL DEFAULT -1, `points` FLOAT NOT NULL DEFAULT 0);", gS_MySQLPrefix);
CreateUsersTable();
}
gH_SQL.Query(SQL_CreateTable_Callback, sQuery, 0, DBPrio_High);
}
public void SQL_CreateTable_Callback(Database db, DBResultSet results, const char[] error, any data)
public void SQL_CreateMigrationsTable_Callback(Database db, DBResultSet results, const char[] error, any data)
{
if(results == null)
{
LogError("Timer error! Users' data table creation failed. Reason: %s", error);
LogError("Timer error! Migrations table creation failed. Reason: %s", error);
return;
}
char sQuery[128];
FormatEx(sQuery, 128, "SELECT code FROM %smigrations;", gS_MySQLPrefix);
gH_SQL.Query(SQL_SelectMigrations_Callback, sQuery, 0, DBPrio_High);
}
public void SQL_SelectMigrations_Callback(Database db, DBResultSet results, const char[] error, any data)
{
if(results == null)
{
LogError("Timer error! Migrations selection failed. Reason: %s", error);
return;
}
// this is ugly, i know. but it works and is more elegant than previous solutions so.. let it be =)
bool bMigrationApplied[255] = { false, ... };
while(results.FetchRow())
{
bMigrationApplied[results.FetchInt(0)] = true;
}
for(int i = 0; i < MIGRATIONS_END; i++)
{
if(!bMigrationApplied[i])
{
PrintToServer("--- Applying database migration %d ---", i);
ApplyMigration(i);
}
}
}
void ApplyMigration(int migration)
{
switch(migration)
{
case Migration_RemoveWorkshopMaptiers, Migration_RemoveWorkshopMapzones, Migration_RemoveWorkshopPlayertimes: ApplyMigration_RemoveWorkshopPath(migration);
case Migration_LastLoginIndex: ApplyMigration_LastLoginIndex();
case Migration_RemoveCountry: ApplyMigration_RemoveCountry();
case Migration_ConvertIPAddresses: ApplyMigration_ConvertIPAddresses();
case Migration_ConvertSteamIDsUsers: ApplyMigration_ConvertSteamIDs();
case Migration_ConvertSteamIDsPlayertimes, Migration_ConvertSteamIDsChat: return; // this is confusing, but the above case handles all of them
case Migration_PlayertimesDateToInt: ApplyMigration_PlayertimesDateToInt();
}
}
void ApplyMigration_LastLoginIndex()
{
char sQuery[128];
FormatEx(sQuery, 128, "ALTER TABLE `%susers` ADD INDEX `lastlogin` (`lastlogin`);", gS_MySQLPrefix);
gH_SQL.Query(SQL_TableMigrationSingleQuery_Callback, sQuery, Migration_LastLoginIndex, DBPrio_High);
}
void ApplyMigration_RemoveCountry()
{
char sQuery[128];
FormatEx(sQuery, 128, "ALTER TABLE `%susers` DROP COLUMN `country`;", gS_MySQLPrefix);
gH_SQL.Query(SQL_TableMigrationSingleQuery_Callback, sQuery, Migration_RemoveCountry, DBPrio_High);
}
void ApplyMigration_PlayertimesDateToInt()
{
char sQuery[128];
FormatEx(sQuery, 128, "ALTER TABLE `%splayertimes` CHANGE COLUMN `date` `date` INT;", gS_MySQLPrefix);
gH_SQL.Query(SQL_TableMigrationSingleQuery_Callback, sQuery, Migration_PlayertimesDateToInt, DBPrio_High);
}
public void SQL_TableMigrationSingleQuery_Callback(Database db, DBResultSet results, const char[] error, any data)
{
InsertMigration(data);
// i hate hardcoding REEEEEEEE
if(data == Migration_ConvertSteamIDsChat)
{
char sQuery[256];
FormatEx(sQuery, 256,
"ALTER TABLE `%splayertimes` ADD CONSTRAINT `pt_auth` FOREIGN KEY (`auth`) REFERENCES `%susers` (`auth`) ON UPDATE CASCADE ON DELETE CASCADE;",
gS_MySQLPrefix, gS_MySQLPrefix);
gH_SQL.Query(SQL_TableMigrationConstraints_Callback, sQuery, 0, DBPrio_High);
FormatEx(sQuery, 256,
"ALTER TABLE `%schat` ADD CONSTRAINT `ch_auth` FOREIGN KEY (`auth`) REFERENCES `%susers` (`auth`) ON UPDATE CASCADE ON DELETE CASCADE;",
gS_MySQLPrefix, gS_MySQLPrefix);
gH_SQL.Query(SQL_TableMigrationConstraints_Callback, sQuery, 0, DBPrio_High);
}
}
void ApplyMigration_ConvertIPAddresses()
{
char sQuery[128];
FormatEx(sQuery, 128, "SELECT DISTINCT ip FROM %susers WHERE ip LIKE \"\%%.\%%\";", gS_MySQLPrefix);
gH_SQL.Query(SQL_TableMigrationIPAddresses_Callback, sQuery, 0, DBPrio_High);
}
public void SQL_TableMigrationIPAddresses_Callback(Database db, DBResultSet results, const char[] error, DataPack data)
{
if(results == null || results.RowCount == 0)
{
InsertMigration(Migration_ConvertIPAddresses);
return;
}
Transaction hTransaction = new Transaction();
while(results.FetchRow())
{
char sIPAddress[32];
results.FetchString(0, sIPAddress, 32);
char sExplodedAddress[4][4];
ExplodeString(sIPAddress, ".", sExplodedAddress, 4, 4, false);
int iIPAddress =
(StringToInt(sExplodedAddress[0]) << 24) |
(StringToInt(sExplodedAddress[1]) << 16) |
(StringToInt(sExplodedAddress[2]) << 8) |
StringToInt(sExplodedAddress[3]);
char sQuery[256];
FormatEx(sQuery, 256, "UPDATE %susers SET ip = %d WHERE ip = '%s';", gS_MySQLPrefix, iIPAddress, sIPAddress);
hTransaction.AddQuery(sQuery);
}
gH_SQL.Execute(hTransaction, Trans_IPAddressMigration);
}
public void Trans_IPAddressMigration(Database db, any data, int numQueries, DBResultSet[] results, any[] queryData)
{
char sQuery[128];
FormatEx(sQuery, 128, "ALTER TABLE `%susers` CHANGE COLUMN `ip` `ip` INT;", gS_MySQLPrefix);
gH_SQL.Query(SQL_TableMigrationSingleQuery_Callback, sQuery, Migration_ConvertIPAddresses, DBPrio_High);
}
void ApplyMigration_ConvertSteamIDs()
{
char sTables[][] =
{
"users",
"playertimes",
"chat"
};
char sQuery[128];
FormatEx(sQuery, 128, "ALTER TABLE `%splayertimes` DROP CONSTRAINT `pt_auth`;", gS_MySQLPrefix);
gH_SQL.Query(SQL_TableMigrationConstraints_Callback, sQuery, 0, DBPrio_High);
FormatEx(sQuery, 128, "ALTER TABLE `%schat` DROP CONSTRAINT `ch_auth`;", gS_MySQLPrefix);
gH_SQL.Query(SQL_TableMigrationConstraints_Callback, sQuery, 0, DBPrio_High);
for(int i = 0; i < sizeof(sTables); i++)
{
DataPack hPack = new DataPack();
hPack.WriteCell(Migration_ConvertSteamIDsUsers + i);
hPack.WriteString(sTables[i]);
FormatEx(sQuery, 128, "UPDATE %s%s SET auth = REPLACE(REPLACE(auth, \"[U:1:\", \"\"), \"]\", \"\") WHERE auth LIKE '[%%';", sTables[i], gS_MySQLPrefix);
gH_SQL.Query(SQL_TableMigrationSteamIDs_Callback, sQuery, hPack, DBPrio_High);
}
}
public void SQL_TableMigrationConstraints_Callback(Database db, DBResultSet results, const char[] error, DataPack data)
{
// nothing
}
public void SQL_TableMigrationSteamIDs_Callback(Database db, DBResultSet results, const char[] error, DataPack data)
{
data.Reset();
int iMigration = data.ReadCell();
char sTable[16];
data.ReadString(sTable, 16);
delete data;
char sQuery[128];
FormatEx(sQuery, 128, "ALTER TABLE `%s%s` CHANGE COLUMN `auth` `auth` INT;", gS_MySQLPrefix, sTable);
gH_SQL.Query(SQL_TableMigrationSingleQuery_Callback, sQuery, iMigration, DBPrio_High);
}
void ApplyMigration_RemoveWorkshopPath(int migration)
{
char sTables[][] =
{
"maptiers",
@ -2245,31 +2425,34 @@ public void SQL_CreateTable_Callback(Database db, DBResultSet results, const cha
for(int i = 0; i < sizeof(sTables); i++)
{
DataPack dp = new DataPack();
dp.WriteString(sTables[i]);
DataPack hPack = new DataPack();
hPack.WriteCell(migration);
hPack.WriteString(sTables[i]);
char sQuery[192];
FormatEx(sQuery, 192, "SELECT map FROM %s%s WHERE map LIKE 'workshop%%' GROUP BY map;", gS_MySQLPrefix, sTables[i]);
gH_SQL.Query(SQL_TableMigration_Callback, sQuery, dp, DBPrio_High);
gH_SQL.Query(SQL_TableMigrationWorkshop_Callback, sQuery, hPack, DBPrio_High);
}
}
Call_StartForward(gH_Forwards_OnDatabaseLoaded);
Call_Finish();
}
public void SQL_TableMigration_Callback(Database db, DBResultSet results, const char[] error, DataPack data)
public void SQL_TableMigrationWorkshop_Callback(Database db, DBResultSet results, const char[] error, DataPack data)
{
char sTable[16];
data.Reset();
int iMigration = data.ReadCell();
char sTable[16];
data.ReadString(sTable, 16);
delete data;
if(results == null || results.RowCount == 0)
{
// no error logging here because not everyone runs the rankings/wr modules
InsertMigration(iMigration);
return;
}
Transaction hTransaction = new Transaction();
while(results.FetchRow())
{
char sMap[160];
@ -2280,18 +2463,62 @@ public void SQL_TableMigration_Callback(Database db, DBResultSet results, const
char sQuery[256];
FormatEx(sQuery, 256, "UPDATE %s%s SET map = '%s' WHERE map = '%s';", gS_MySQLPrefix, sTable, sDisplayMap, sMap);
gH_SQL.Query(SQL_AlterTable3_Callback, sQuery, 0, DBPrio_High);
}
hTransaction.AddQuery(sQuery);
}
public void SQL_AlterTable3_Callback(Database db, DBResultSet results, const char[] error, any data)
gH_SQL.Execute(hTransaction, Trans_WorkshopMigration, INVALID_FUNCTION, iMigration);
}
public void Trans_WorkshopMigration(Database db, any data, int numQueries, DBResultSet[] results, any[] queryData)
{
InsertMigration(data);
}
void InsertMigration(int migration)
{
char sQuery[128];
FormatEx(sQuery, 128, "INSERT INTO %smigrations (code) VALUES (%d);", gS_MySQLPrefix, migration);
gH_SQL.Query(SQL_MigrationApplied_Callback, sQuery, migration);
}
public void SQL_MigrationApplied_Callback(Database db, DBResultSet results, const char[] error, any data)
{
// nothing
}
void CreateUsersTable()
{
char sQuery[512];
if(gB_MySQL)
{
FormatEx(sQuery, 512,
"CREATE TABLE IF NOT EXISTS `%susers` (`auth` INT NOT NULL, `name` VARCHAR(32) COLLATE 'utf8mb4_general_ci', `ip` INT, `lastlogin` INT NOT NULL DEFAULT -1, `points` FLOAT NOT NULL DEFAULT 0, PRIMARY KEY (`auth`), INDEX `points` (`points`), INDEX `lastlogin` (`lastlogin`)) ENGINE=INNODB;",
gS_MySQLPrefix);
}
else
{
FormatEx(sQuery, 512,
"CREATE TABLE IF NOT EXISTS `%susers` (`auth` INT NOT NULL PRIMARY KEY, `name` VARCHAR(32), `ip` INT, `lastlogin` INTEGER NOT NULL DEFAULT -1, `points` FLOAT NOT NULL DEFAULT 0);",
gS_MySQLPrefix);
}
gH_SQL.Query(SQL_CreateUsersTable_Callback, sQuery, 0, DBPrio_High);
}
public void SQL_CreateUsersTable_Callback(Database db, DBResultSet results, const char[] error, any data)
{
if(results == null)
{
LogError("Timer error! Table alteration 3 (core) failed. Reason: %s", error);
LogError("Timer error! Users' data table creation failed. Reason: %s", error);
return;
}
Call_StartForward(gH_Forwards_OnDatabaseLoaded);
Call_Finish();
}
public void PreThinkPost(int client)

View File

@ -75,7 +75,7 @@ enum struct player_cpcache_t
enum struct persistent_data_t
{
char sAuthID[32];
int iSteamID;
float fDisconnectTime;
float fPosition[3];
float fAngles[3];
@ -1127,7 +1127,7 @@ void PersistData(int client)
if(!IsClientInGame(client) ||
!IsPlayerAlive(client) ||
!GetClientAuthId(client, AuthId_Steam3, aData.sAuthID, 32) ||
(aData.iSteamID = GetSteamAccountID((client))) == 0 ||
Shavit_GetTimerStatus(client) == Timer_Stopped ||
gCV_PersistData.IntValue == 0)
{
@ -1188,11 +1188,11 @@ void DeletePersistentData(int index, persistent_data_t data)
public Action Timer_LoadPersistentData(Handle Timer, any data)
{
char sAuthID[32];
int iSteamID = 0;
int client = GetClientFromSerial(data);
if(client == 0 ||
!GetClientAuthId(client, AuthId_Steam3, sAuthID, 32) ||
(iSteamID = GetSteamAccountID(client)) == 0 ||
GetClientTeam(client) < 2 ||
!IsPlayerAlive(client))
{
@ -1207,7 +1207,7 @@ public Action Timer_LoadPersistentData(Handle Timer, any data)
{
gA_PersistentData.GetArray(i, aData);
if(StrEqual(sAuthID, aData.sAuthID))
if(iSteamID == aData.iSteamID)
{
iIndex = i;

View File

@ -312,7 +312,7 @@ public void SQL_CreateTable_Callback(Database db, DBResultSet results, const cha
bool bSuccess = true;
RunLongFastQuery(bSuccess, "CREATE GetWeightedPoints",
"CREATE FUNCTION GetWeightedPoints(authid VARCHAR(32)) " ...
"CREATE FUNCTION GetWeightedPoints(steamid INT) " ...
"RETURNS FLOAT " ...
"READS SQL DATA " ...
"BEGIN " ...
@ -320,7 +320,7 @@ public void SQL_CreateTable_Callback(Database db, DBResultSet results, const cha
"DECLARE total FLOAT DEFAULT 0.0; " ...
"DECLARE mult FLOAT DEFAULT 1.0; " ...
"DECLARE done INT DEFAULT 0; " ...
"DECLARE cur CURSOR FOR SELECT points FROM %splayertimes WHERE auth = authid AND points > 0.0 ORDER BY points DESC; " ...
"DECLARE cur CURSOR FOR SELECT points FROM %splayertimes WHERE auth = steamid AND points > 0.0 ORDER BY points DESC; " ...
"DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1; " ...
"OPEN cur; " ...
"iter: LOOP " ...
@ -610,7 +610,7 @@ public int MenuHandler_Top(Menu menu, MenuAction action, int param1, int param2)
if(gB_Stats && !StrEqual(sInfo, "-1"))
{
Shavit_OpenStatsMenu(param1, sInfo);
Shavit_OpenStatsMenu(param1, StringToInt(sInfo));
}
}
@ -823,15 +823,15 @@ void UpdatePlayerRank(int client, bool first)
gA_Rankings[client].iRank = 0;
gA_Rankings[client].fPoints = 0.0;
char sAuthID[32];
int iSteamID = 0;
if(GetClientAuthId(client, AuthId_Steam3, sAuthID, 32))
if((iSteamID = GetSteamAccountID(client)) != 0)
{
// if there's any issue with this query,
// add "ORDER BY points DESC " before "LIMIT 1"
char sQuery[512];
FormatEx(sQuery, 512, "SELECT u2.points, COUNT(*) FROM %susers u1 JOIN (SELECT points FROM %susers WHERE auth = '%s') u2 WHERE u1.points >= u2.points;",
gS_MySQLPrefix, gS_MySQLPrefix, sAuthID);
FormatEx(sQuery, 512, "SELECT u2.points, COUNT(*) FROM %susers u1 JOIN (SELECT points FROM %susers WHERE auth = %d) u2 WHERE u1.points >= u2.points;",
gS_MySQLPrefix, gS_MySQLPrefix, iSteamID);
DataPack hPack = new DataPack();
hPack.WriteCell(GetClientSerial(client));
@ -936,8 +936,8 @@ public void SQL_UpdateTop100_Callback(Database db, DBResultSet results, const ch
break;
}
char sAuthID[32];
results.FetchString(0, sAuthID, 32);
char sSteamID[32];
results.FetchString(0, sSteamID, 32);
char sName[MAX_NAME_LENGTH];
results.FetchString(1, sName, MAX_NAME_LENGTH);
@ -947,7 +947,7 @@ public void SQL_UpdateTop100_Callback(Database db, DBResultSet results, const ch
char sDisplay[96];
FormatEx(sDisplay, 96, "#%d - %s (%s)", (++row), sName, sPoints);
gH_Top100Menu.AddItem(sAuthID, sDisplay);
gH_Top100Menu.AddItem(sSteamID, sDisplay);
}
if(gH_Top100Menu.ItemCount == 0)

View File

@ -33,7 +33,7 @@
#define REPLAY_FORMAT_V2 "{SHAVITREPLAYFORMAT}{V2}"
#define REPLAY_FORMAT_FINAL "{SHAVITREPLAYFORMAT}{FINAL}"
#define REPLAY_FORMAT_SUBVERSION 0x03
#define REPLAY_FORMAT_SUBVERSION 0x04
#define CELLS_PER_FRAME 8 // origin[3], angles[2], buttons, flags, movetype
#define FRAMES_PER_WRITE 100 // amounts of frames to write per read/write call
@ -1015,19 +1015,32 @@ bool LoadCurrentReplayFormat(File file, int version, int style, int track)
file.ReadInt32(iTemp);
gA_FrameCache[style][track].fTime = view_as<float>(iTemp);
int iSteamID = 0;
if(gA_FrameCache[style][track].iReplayVersion >= 0x04)
{
file.ReadInt32(iSteamID);
}
else
{
char sAuthID[32];
file.ReadString(sAuthID, 32);
ReplaceString(sAuthID, 32, "[U:1:", "");
ReplaceString(sAuthID, 32, "]", "");
iSteamID = StringToInt(sAuthID);
}
if(gH_SQL != null)
{
char sQuery[192];
FormatEx(sQuery, 192, "SELECT name FROM %susers WHERE auth = '%s';", gS_MySQLPrefix, sAuthID);
FormatEx(sQuery, 192, "SELECT name FROM %susers WHERE auth = %d;", gS_MySQLPrefix, iSteamID);
DataPack pack = new DataPack();
pack.WriteCell(style);
pack.WriteCell(track);
DataPack hPack = new DataPack();
hPack.WriteCell(style);
hPack.WriteCell(track);
gH_SQL.Query(SQL_GetUserName_Callback, sQuery, pack, DBPrio_High);
gH_SQL.Query(SQL_GetUserName_Callback, sQuery, hPack, DBPrio_High);
}
int cells = CELLS_PER_FRAME;
@ -1169,7 +1182,7 @@ bool LoadReplay(int style, int track, const char[] path)
return false;
}
bool SaveReplay(int style, int track, float time, char[] authid, char[] name, int preframes = 0)
bool SaveReplay(int style, int track, float time, int steamid, char[] name, int preframes = 0)
{
char sTrack[4];
FormatEx(sTrack, 4, "_%d", track);
@ -1193,7 +1206,7 @@ bool SaveReplay(int style, int track, float time, char[] authid, char[] name, in
int iSize = gA_Frames[style][track].Length;
fFile.WriteInt32(iSize);
fFile.WriteInt32(view_as<int>(time));
fFile.WriteString(authid, true);
fFile.WriteInt32(steamid);
any aFrameData[CELLS_PER_FRAME];
any aWriteData[CELLS_PER_FRAME * FRAMES_PER_WRITE];
@ -1599,14 +1612,13 @@ public void Shavit_OnFinish(int client, int style, float time, int jumps, int st
delete gA_Frames[style][track];
gA_Frames[style][track] = gA_PlayerFrames[client].Clone();
char sAuthID[32];
GetClientAuthId(client, AuthId_Steam3, sAuthID, 32);
int iSteamID = GetSteamAccountID(client);
char sName[MAX_NAME_LENGTH];
GetClientName(client, sName, MAX_NAME_LENGTH);
ReplaceString(sName, MAX_NAME_LENGTH, "#", "?");
SaveReplay(style, track, time, sAuthID, sName);
SaveReplay(style, track, time, iSteamID, sName);
if(ReplayEnabled(style))
{

View File

@ -48,7 +48,7 @@ bool gB_AllowStats[MAXPLAYERS+1];
int gI_MapType[MAXPLAYERS+1];
int gI_Style[MAXPLAYERS+1];
int gI_Track[MAXPLAYERS+1];
char gS_TargetAuth[MAXPLAYERS+1][32];
int gI_TargetSteamID[MAXPLAYERS+1];
char gS_TargetName[MAXPLAYERS+1][MAX_NAME_LENGTH];
int gI_WRAmount[MAXPLAYERS+1];
EngineVersion gEV_Type = Engine_Unknown;
@ -282,9 +282,9 @@ void UpdateWRs(int client)
return;
}
char sAuthID[32];
int iSteamID = 0;
if(GetClientAuthId(client, AuthId_Steam3, sAuthID, 32))
if((iSteamID = GetSteamAccountID(client)) != 0)
{
char sQuery[512];
@ -292,16 +292,16 @@ void UpdateWRs(int client)
if(gCV_MVPRankOnes.IntValue == 2)
{
FormatEx(sQuery, 512,
"SELECT COUNT(*) FROM %splayertimes a JOIN (SELECT MIN(time) time, map FROM %splayertimes WHERE style = 0 %sGROUP by map, track) b ON a.time = b.time AND a.map = b.map AND style = 0 %sWHERE auth = '%s';",
gS_MySQLPrefix, gS_MySQLPrefix, (gCV_MVPRankOnes_Main.BoolValue)? "AND track = 0 ":"", (gCV_MVPRankOnes_Main.BoolValue)? "AND track = 0 ":"", sAuthID);
"SELECT COUNT(*) FROM %splayertimes a JOIN (SELECT MIN(time) time, map FROM %splayertimes WHERE style = 0 %sGROUP by map, track) b ON a.time = b.time AND a.map = b.map AND style = 0 %sWHERE auth = %d;",
gS_MySQLPrefix, gS_MySQLPrefix, (gCV_MVPRankOnes_Main.BoolValue)? "AND track = 0 ":"", (gCV_MVPRankOnes_Main.BoolValue)? "AND track = 0 ":"", iSteamID);
}
// all styles
else
{
FormatEx(sQuery, 512,
"SELECT COUNT(*) FROM %splayertimes a JOIN (SELECT MIN(time) time, map, style FROM %splayertimes %sGROUP by map, style, track) b ON a.time = b.time AND a.map = b.map AND a.style = b.style %sWHERE auth = '%s';",
gS_MySQLPrefix, gS_MySQLPrefix, (gCV_MVPRankOnes_Main.BoolValue)? "WHERE track = 0 ":"", (gCV_MVPRankOnes_Main.BoolValue)? "AND track = 0 ":"", sAuthID);
"SELECT COUNT(*) FROM %splayertimes a JOIN (SELECT MIN(time) time, map, style FROM %splayertimes %sGROUP by map, style, track) b ON a.time = b.time AND a.map = b.map AND a.style = b.style %sWHERE auth = %d;",
gS_MySQLPrefix, gS_MySQLPrefix, (gCV_MVPRankOnes_Main.BoolValue)? "WHERE track = 0 ":"", (gCV_MVPRankOnes_Main.BoolValue)? "AND track = 0 ":"", iSteamID);
}
gH_SQL.Query(SQL_GetWRs_Callback, sQuery, GetClientSerial(client));
@ -356,7 +356,7 @@ public Action Command_MapsDoneLeft(int client, int args)
}
}
GetClientAuthId(target, AuthId_Steam3, gS_TargetAuth[client], 32);
gI_TargetSteamID[client] = GetSteamAccountID(target);
char sCommand[16];
GetCmdArg(0, sCommand, 16);
@ -472,12 +472,12 @@ public Action Command_Profile(int client, int args)
}
}
GetClientAuthId(target, AuthId_Steam3, gS_TargetAuth[client], 32);
gI_TargetSteamID[client] = GetSteamAccountID(target);
return OpenStatsMenu(client, gS_TargetAuth[client]);
return OpenStatsMenu(client, gI_TargetSteamID[client]);
}
Action OpenStatsMenu(int client, const char[] authid)
Action OpenStatsMenu(int client, int steamid)
{
// no spam please
if(!gB_AllowStats[client])
@ -490,23 +490,23 @@ Action OpenStatsMenu(int client, const char[] authid)
if(gB_Rankings)
{
FormatEx(sQuery, 2048, "SELECT a.clears, b.maps, c.wrs, d.name, d.country, d.lastlogin, d.points, e.rank FROM " ...
"(SELECT COUNT(*) clears FROM (SELECT map FROM %splayertimes WHERE auth = '%s' AND track = 0 GROUP BY map) s) a " ...
FormatEx(sQuery, 2048, "SELECT a.clears, b.maps, c.wrs, d.name, d.ip, d.lastlogin, d.points, e.rank FROM " ...
"(SELECT COUNT(*) clears FROM (SELECT map FROM %splayertimes WHERE auth = %d AND track = 0 GROUP BY map) s) a " ...
"JOIN (SELECT COUNT(*) maps FROM (SELECT map FROM %smapzones WHERE track = 0 AND type = 0 GROUP BY map) s) b " ...
"JOIN (SELECT COUNT(*) wrs FROM %splayertimes a JOIN (SELECT MIN(time) time, map FROM %splayertimes WHERE style = 0 AND track = 0 GROUP by map, style, track) b ON a.time = b.time AND a.map = b.map AND track = 0 AND style = 0 WHERE auth = '%s') c " ...
"JOIN (SELECT name, country, lastlogin, FORMAT(points, 2) points FROM %susers WHERE auth = '%s') d " ...
"JOIN (SELECT COUNT(*) rank FROM %susers u1 JOIN (SELECT points FROM %susers WHERE auth = '%s') u2 WHERE u1.points >= u2.points) e " ...
"LIMIT 1;", gS_MySQLPrefix, authid, gS_MySQLPrefix, gS_MySQLPrefix, gS_MySQLPrefix, authid, gS_MySQLPrefix, authid, gS_MySQLPrefix, gS_MySQLPrefix, authid);
"JOIN (SELECT COUNT(*) wrs FROM %splayertimes a JOIN (SELECT MIN(time) time, map FROM %splayertimes WHERE style = 0 AND track = 0 GROUP by map, style, track) b ON a.time = b.time AND a.map = b.map AND track = 0 AND style = 0 WHERE auth = %d) c " ...
"JOIN (SELECT name, ip, lastlogin, FORMAT(points, 2) points FROM %susers WHERE auth = %d) d " ...
"JOIN (SELECT COUNT(*) rank FROM %susers u1 JOIN (SELECT points FROM %susers WHERE auth = %d) u2 WHERE u1.points >= u2.points) e " ...
"LIMIT 1;", gS_MySQLPrefix, steamid, gS_MySQLPrefix, gS_MySQLPrefix, gS_MySQLPrefix, steamid, gS_MySQLPrefix, steamid, gS_MySQLPrefix, gS_MySQLPrefix, steamid);
}
else
{
FormatEx(sQuery, 2048, "SELECT a.clears, b.maps, c.wrs, d.name, d.country, d.lastlogin FROM " ...
"(SELECT COUNT(*) clears FROM (SELECT map FROM %splayertimes WHERE auth = '%s' AND track = 0 GROUP BY map) s) a " ...
FormatEx(sQuery, 2048, "SELECT a.clears, b.maps, c.wrs, d.name, d.ip, d.lastlogin FROM " ...
"(SELECT COUNT(*) clears FROM (SELECT map FROM %splayertimes WHERE auth = %d AND track = 0 GROUP BY map) s) a " ...
"JOIN (SELECT COUNT(*) maps FROM (SELECT map FROM %smapzones WHERE track = 0 AND type = 0 GROUP BY map) s) b " ...
"JOIN (SELECT COUNT(*) wrs FROM %splayertimes a JOIN (SELECT MIN(time) time, map FROM %splayertimes WHERE style = 0 AND track = 0 GROUP by map, style, track) b ON a.time = b.time AND a.map = b.map AND track = 0 AND style = 0 WHERE auth = '%s') c " ...
"JOIN (SELECT name, country, lastlogin FROM %susers WHERE auth = '%s') d " ...
"LIMIT 1;", gS_MySQLPrefix, authid, gS_MySQLPrefix, gS_MySQLPrefix, gS_MySQLPrefix, authid, gS_MySQLPrefix, authid);
"JOIN (SELECT COUNT(*) wrs FROM %splayertimes a JOIN (SELECT MIN(time) time, map FROM %splayertimes WHERE style = 0 AND track = 0 GROUP by map, style, track) b ON a.time = b.time AND a.map = b.map AND track = 0 AND style = 0 WHERE auth = %d) c " ...
"JOIN (SELECT name, ip, lastlogin FROM %susers WHERE auth = %d) d " ...
"LIMIT 1;", gS_MySQLPrefix, steamid, gS_MySQLPrefix, gS_MySQLPrefix, gS_MySQLPrefix, steamid, gS_MySQLPrefix, steamid);
}
gB_AllowStats[client] = false;
@ -541,8 +541,16 @@ public void OpenStatsMenuCallback(Database db, DBResultSet results, const char[]
results.FetchString(3, gS_TargetName[client], MAX_NAME_LENGTH);
ReplaceString(gS_TargetName[client], MAX_NAME_LENGTH, "#", "?");
int iIPAddress = results.FetchInt(4);
char sIPAddress[32];
IPAddressToString(iIPAddress, sIPAddress, 32);
char sCountry[64];
results.FetchString(4, sCountry, 64);
if(!GeoipCountry(sIPAddress, sCountry, 64))
{
strcopy(sCountry, 64, "Local Area Network");
}
int iLastLogin = results.FetchInt(5);
char sLastLogin[32];
@ -582,8 +590,8 @@ public void OpenStatsMenuCallback(Database db, DBResultSet results, const char[]
FormatEx(sClearString, 128, "%T: %d/%d (%.01f%%)", "MapCompletions", client, iClears, iTotalMaps, ((float(iClears) / iTotalMaps) * 100.0));
Menu menu = new Menu(MenuHandler_ProfileHandler);
menu.SetTitle("%s's %T. %s\n%T: %s\n%s\n%s\n[%s] %T: %d%s\n",
gS_TargetName[client], "Profile", client, gS_TargetAuth[client], "Country", client, sCountry, sLastLogin, sClearString,
menu.SetTitle("%s's %T. [U:1:%d]\n%T: %s\n%s\n%s\n[%s] %T: %d%s\n",
gS_TargetName[client], "Profile", client, gI_TargetSteamID[client], "Country", client, sCountry, sLastLogin, sClearString,
gS_StyleStrings[0].sStyleName, "WorldRecords", client, iWRs, sRankingString);
int[] styles = new int[gI_Styles];
@ -681,7 +689,7 @@ public int MenuHandler_TypeHandler(Menu menu, MenuAction action, int param1, int
else if(action == MenuAction_Cancel && param2 == MenuCancel_ExitBack)
{
OpenStatsMenu(param1, gS_TargetAuth[param1]);
OpenStatsMenu(param1, gI_TargetSteamID[param1]);
}
else if(action == MenuAction_End)
@ -721,8 +729,8 @@ void ShowMaps(int client)
if(gI_MapType[client] == MAPSDONE)
{
FormatEx(sQuery, 512,
"SELECT a.map, a.time, a.jumps, a.id, COUNT(b.map) + 1 rank, a.points FROM %splayertimes a LEFT JOIN %splayertimes b ON a.time > b.time AND a.map = b.map AND a.style = b.style AND a.track = b.track WHERE a.auth = '%s' AND a.style = %d AND a.track = %d GROUP BY a.map, a.time, a.jumps, a.id, a.points ORDER BY a.%s;",
gS_MySQLPrefix, gS_MySQLPrefix, gS_TargetAuth[client], gI_Style[client], gI_Track[client], (gB_Rankings)? "points DESC":"map");
"SELECT a.map, a.time, a.jumps, a.id, COUNT(b.map) + 1 rank, a.points FROM %splayertimes a LEFT JOIN %splayertimes b ON a.time > b.time AND a.map = b.map AND a.style = b.style AND a.track = b.track WHERE a.auth = %d AND a.style = %d AND a.track = %d GROUP BY a.map, a.time, a.jumps, a.id, a.points ORDER BY a.%s;",
gS_MySQLPrefix, gS_MySQLPrefix, gI_TargetSteamID[client], gI_Style[client], gI_Track[client], (gB_Rankings)? "points DESC":"map");
}
else
@ -730,15 +738,15 @@ void ShowMaps(int client)
if(gB_Rankings)
{
FormatEx(sQuery, 512,
"SELECT DISTINCT m.map, t.tier FROM %smapzones m LEFT JOIN %smaptiers t ON m.map = t.map WHERE m.type = 0 AND m.track = %d AND m.map NOT IN (SELECT DISTINCT map FROM %splayertimes WHERE auth = '%s' AND style = %d AND track = %d) ORDER BY m.map;",
gS_MySQLPrefix, gS_MySQLPrefix, gI_Track[client], gS_MySQLPrefix, gS_TargetAuth[client], gI_Style[client], gI_Track[client]);
"SELECT DISTINCT m.map, t.tier FROM %smapzones m LEFT JOIN %smaptiers t ON m.map = t.map WHERE m.type = 0 AND m.track = %d AND m.map NOT IN (SELECT DISTINCT map FROM %splayertimes WHERE auth = %d AND style = %d AND track = %d) ORDER BY m.map;",
gS_MySQLPrefix, gS_MySQLPrefix, gI_Track[client], gS_MySQLPrefix, gI_TargetSteamID[client], gI_Style[client], gI_Track[client]);
}
else
{
FormatEx(sQuery, 512,
"SELECT DISTINCT map FROM %smapzones WHERE type = 0 AND track = %d AND map NOT IN (SELECT DISTINCT map FROM %splayertimes WHERE auth = '%s' AND style = %d AND track = %d) ORDER BY map;",
gS_MySQLPrefix, gI_Track[client], gS_MySQLPrefix, gS_TargetAuth[client], gI_Style[client], gI_Track[client]);
"SELECT DISTINCT map FROM %smapzones WHERE type = 0 AND track = %d AND map NOT IN (SELECT DISTINCT map FROM %splayertimes WHERE auth = %d AND style = %d AND track = %d) ORDER BY map;",
gS_MySQLPrefix, gI_Track[client], gS_MySQLPrefix, gI_TargetSteamID[client], gI_Style[client], gI_Track[client]);
}
}
@ -853,7 +861,7 @@ public int MenuHandler_ShowMaps(Menu menu, MenuAction action, int param1, int pa
if(StrEqual(sInfo, "nope"))
{
OpenStatsMenu(param1, gS_TargetAuth[param1]);
OpenStatsMenu(param1, gI_TargetSteamID[param1]);
return 0;
}
@ -866,7 +874,7 @@ public int MenuHandler_ShowMaps(Menu menu, MenuAction action, int param1, int pa
else if(action == MenuAction_Cancel && param2 == MenuCancel_ExitBack)
{
OpenStatsMenu(param1, gS_TargetAuth[param1]);
OpenStatsMenu(param1, gI_TargetSteamID[param1]);
}
else if(action == MenuAction_End)
@ -893,10 +901,10 @@ public void SQL_SubMenu_Callback(Database db, DBResultSet results, const char[]
return;
}
Menu menu = new Menu(SubMenu_Handler);
Menu hMenu = new Menu(SubMenu_Handler);
char sName[MAX_NAME_LENGTH];
char sAuthID[32];
int iSteamID = 0;
char sMap[192];
if(results.FetchRow())
@ -911,20 +919,20 @@ public void SQL_SubMenu_Callback(Database db, DBResultSet results, const char[]
char sDisplay[128];
FormatEx(sDisplay, 128, "%T: %s", "Time", client, sTime);
menu.AddItem("-1", sDisplay);
hMenu.AddItem("-1", sDisplay);
// 2 - jumps
int jumps = results.FetchInt(2);
FormatEx(sDisplay, 128, "%T: %d", "Jumps", client, jumps);
menu.AddItem("-1", sDisplay);
hMenu.AddItem("-1", sDisplay);
// 3 - style
int style = results.FetchInt(3);
FormatEx(sDisplay, 128, "%T: %s", "Style", client, gS_StyleStrings[style].sStyleName);
menu.AddItem("-1", sDisplay);
hMenu.AddItem("-1", sDisplay);
// 4 - steamid3
results.FetchString(4, sAuthID, 32);
iSteamID = results.FetchInt(4);
// 6 - map
results.FetchString(6, sMap, 192);
@ -934,7 +942,7 @@ public void SQL_SubMenu_Callback(Database db, DBResultSet results, const char[]
if(gB_Rankings && points > 0.0)
{
FormatEx(sDisplay, 192, "%T: %.03f", "Points", client, points);
menu.AddItem("-1", sDisplay);
hMenu.AddItem("-1", sDisplay);
}
// 5 - date
@ -947,7 +955,7 @@ public void SQL_SubMenu_Callback(Database db, DBResultSet results, const char[]
}
FormatEx(sDisplay, 128, "%T: %s", "Date", client, sDate);
menu.AddItem("-1", sDisplay);
hMenu.AddItem("-1", sDisplay);
int strafes = results.FetchInt(7);
float sync = results.FetchFloat(8);
@ -955,16 +963,16 @@ public void SQL_SubMenu_Callback(Database db, DBResultSet results, const char[]
if(jumps > 0 || strafes > 0)
{
FormatEx(sDisplay, 128, (sync > 0.0)? "%T: %d (%.02f%%)":"%T: %d", "Strafes", client, strafes, sync, "Strafes", client, strafes);
menu.AddItem("-1", sDisplay);
hMenu.AddItem("-1", sDisplay);
}
}
char sFormattedTitle[256];
FormatEx(sFormattedTitle, 256, "%s %s\n--- %s:", sName, sAuthID, sMap);
FormatEx(sFormattedTitle, 256, "%s [U:1:%d]\n--- %s:", sName, iSteamID, sMap);
menu.SetTitle(sFormattedTitle);
menu.ExitBackButton = true;
menu.Display(client, 20);
hMenu.SetTitle(sFormattedTitle);
hMenu.ExitBackButton = true;
hMenu.Display(client, 20);
}
public int SubMenu_Handler(Menu menu, MenuAction action, int param1, int param2)
@ -985,9 +993,9 @@ public int SubMenu_Handler(Menu menu, MenuAction action, int param1, int param2)
public int Native_OpenStatsMenu(Handle handler, int numParams)
{
int client = GetNativeCell(1);
GetNativeString(2, gS_TargetAuth[client], 32);
gI_TargetSteamID[client] = GetNativeCell(2);
OpenStatsMenu(client, gS_TargetAuth[client]);
OpenStatsMenu(client, gI_TargetSteamID[client]);
}
public int Native_GetWRCount(Handle handler, int numParams)

View File

@ -426,11 +426,15 @@ public void OnClientPutInServer(int client)
void UpdateClientCache(int client)
{
char sAuthID[32];
GetClientAuthId(client, AuthId_Steam3, sAuthID, 32);
int iSteamID = GetSteamAccountID(client);
if(iSteamID == 0)
{
return;
}
char sQuery[256];
FormatEx(sQuery, 256, "SELECT time, style, track FROM %splayertimes WHERE map = '%s' AND auth = '%s';", gS_MySQLPrefix, gS_Map, sAuthID);
FormatEx(sQuery, 256, "SELECT time, style, track FROM %splayertimes WHERE map = '%s' AND auth = %d;", gS_MySQLPrefix, gS_Map, iSteamID);
gH_SQL.Query(SQL_UpdateCache_Callback, sQuery, GetClientSerial(client), DBPrio_High);
}
@ -635,10 +639,9 @@ public void SQL_DeleteMap_Callback(Database db, DBResultSet results, const char[
public Action Command_Junk(int client, int args)
{
char sQuery[256];
char sAuth[32];
GetClientAuthId(client, AuthId_Steam3, sAuth, 32);
FormatEx(sQuery, 256, "INSERT INTO %splayertimes (auth, map, time, jumps, date, style, strafes, sync) VALUES ('%s', '%s', %f, %d, %d, 0, %d, %.02f);", gS_MySQLPrefix, sAuth, gS_Map, GetRandomFloat(10.0, 20.0), GetRandomInt(5, 15), GetTime(), GetRandomInt(5, 15), GetRandomFloat(50.0, 99.99));
FormatEx(sQuery, 256,
"INSERT INTO %splayertimes (auth, map, time, jumps, date, style, strafes, sync) VALUES (%d, '%s', %f, %d, %d, 0, %d, %.02f);",
gS_MySQLPrefix, GetSteamAccountID(client), gS_Map, GetRandomFloat(10.0, 20.0), GetRandomInt(5, 15), GetTime(), GetRandomInt(5, 15), GetRandomFloat(50.0, 99.99));
SQL_LockDatabase(gH_SQL);
SQL_FastQuery(gH_SQL, sQuery);
@ -1125,8 +1128,7 @@ public void GetRecordDetails_Callback(Database db, DBResultSet results, const ch
if(results.FetchRow())
{
char sAuthID[32];
results.FetchString(0, sAuthID, 32);
int iSteamID = results.FetchInt(0);
char sName[MAX_NAME_LENGTH];
results.FetchString(1, sName, MAX_NAME_LENGTH);
@ -1150,7 +1152,7 @@ public void GetRecordDetails_Callback(Database db, DBResultSet results, const ch
// that's a big datapack ya yeet
DataPack hPack = new DataPack();
hPack.WriteCell(GetClientSerial(client));
hPack.WriteString(sAuthID);
hPack.WriteCell(iSteamID);
hPack.WriteString(sName);
hPack.WriteString(sMap);
hPack.WriteCell(fTime);
@ -1178,9 +1180,7 @@ public void DeleteConfirm_Callback(Database db, DBResultSet results, const char[
hPack.Reset();
int iSerial = hPack.ReadCell();
char sAuthID[32];
hPack.ReadString(sAuthID, 32);
int iSteamID = hPack.ReadCell();
char sName[MAX_NAME_LENGTH];
hPack.ReadString(sName, MAX_NAME_LENGTH);
@ -1234,8 +1234,8 @@ public void DeleteConfirm_Callback(Database db, DBResultSet results, const char[
FormatTime(sDate, 32, "%Y-%m-%d %H:%M:%S", iTimestamp);
// above the client == 0 so log doesn't get lost if admin disconnects between deleting record and query execution
Shavit_LogMessage("%L - deleted record. Runner: %s (%s) | Map: %s | Style: %s | Track: %s | Time: %.2f (%s) | Strafes: %d (%.1f%%) | Jumps: %d (%.1f%%) | Run date: %s | Record ID: %d",
client, sName, sAuthID, sMap, gS_StyleStrings[iStyle].sStyleName, sTrack, fTime, (bWRDeleted)? "WR":"not WR", iStrafes, fSync, iJumps, fPerfectJumps, sDate, iRecordID);
Shavit_LogMessage("%L - deleted record. Runner: %s ([U:1:%d]) | Map: %s | Style: %s | Track: %s | Time: %.2f (%s) | Strafes: %d (%.1f%%) | Jumps: %d (%.1f%%) | Run date: %s | Record ID: %d",
client, sName, iSteamID, sMap, gS_StyleStrings[iStyle].sStyleName, sTrack, fTime, (bWRDeleted)? "WR":"not WR", iStrafes, fSync, iJumps, fPerfectJumps, sDate, iRecordID);
if(client == 0)
{
@ -1448,10 +1448,9 @@ public void SQL_WR_Callback(Database db, DBResultSet results, const char[] error
return;
}
char sAuth[32];
GetClientAuthId(client, AuthId_Steam3, sAuth, 32);
int iSteamID = GetSteamAccountID(client);
Menu menu = new Menu(WRMenu_Handler);
Menu hMenu = new Menu(WRMenu_Handler);
int iCount = 0;
int iMyRank = 0;
@ -1479,14 +1478,13 @@ public void SQL_WR_Callback(Database db, DBResultSet results, const char[] error
char sDisplay[128];
FormatEx(sDisplay, 128, "#%d - %s - %s (%d %T)", iCount, sName, sTime, jumps, "WRJumps", client);
menu.AddItem(sID, sDisplay);
hMenu.AddItem(sID, sDisplay);
}
// check if record exists in the map's top X
char sQueryAuth[32];
results.FetchString(4, sQueryAuth, 32);
int iQuerySteamID = results.FetchInt(4);
if(StrEqual(sQueryAuth, sAuth))
if(iQuerySteamID == iSteamID)
{
iMyRank = iCount;
}
@ -1494,13 +1492,13 @@ public void SQL_WR_Callback(Database db, DBResultSet results, const char[] error
char sFormattedTitle[256];
if(menu.ItemCount == 0)
if(hMenu.ItemCount == 0)
{
menu.SetTitle("%T", "WRMap", client, sMap);
hMenu.SetTitle("%T", "WRMap", client, sMap);
char sNoRecords[64];
FormatEx(sNoRecords, 64, "%T", "WRMapNoRecords", client);
menu.AddItem("-1", sNoRecords);
hMenu.AddItem("-1", sNoRecords);
}
else
@ -1525,11 +1523,11 @@ public void SQL_WR_Callback(Database db, DBResultSet results, const char[] error
GetTrackName(client, track, sTrack, 32);
FormatEx(sFormattedTitle, 192, "%T %s: [%s]\n%s", "WRRecordFor", client, sMap, sTrack, sRanks);
menu.SetTitle(sFormattedTitle);
hMenu.SetTitle(sFormattedTitle);
}
menu.ExitBackButton = true;
menu.Display(client, 20);
hMenu.ExitBackButton = true;
hMenu.Display(client, 20);
}
public int WRMenu_Handler(Menu menu, MenuAction action, int param1, int param2)
@ -1722,11 +1720,11 @@ public void SQL_SubMenu_Callback(Database db, DBResultSet results, const char[]
return;
}
Menu menu = new Menu(SubMenu_Handler);
Menu hMenu = new Menu(SubMenu_Handler);
char sFormattedTitle[256];
char sName[MAX_NAME_LENGTH];
char sAuthID[32];
int iSteamID = 0;
char sTrack[32];
char sMap[192];
@ -1742,7 +1740,7 @@ public void SQL_SubMenu_Callback(Database db, DBResultSet results, const char[]
char sDisplay[128];
FormatEx(sDisplay, 128, "%T: %s", "WRTime", client, sTime);
menu.AddItem("-1", sDisplay);
hMenu.AddItem("-1", sDisplay);
// 2 - jumps
int style = results.FetchInt(3);
@ -1759,11 +1757,11 @@ public void SQL_SubMenu_Callback(Database db, DBResultSet results, const char[]
FormatEx(sDisplay, 128, "%T: %d (%.2f%%)", "WRJumps", client, jumps, perfs);
}
menu.AddItem("-1", sDisplay);
hMenu.AddItem("-1", sDisplay);
// 3 - style
FormatEx(sDisplay, 128, "%T: %s", "WRStyle", client, gS_StyleStrings[style].sStyleName);
menu.AddItem("-1", sDisplay);
hMenu.AddItem("-1", sDisplay);
// 6 - map
results.FetchString(6, sMap, 192);
@ -1773,11 +1771,11 @@ public void SQL_SubMenu_Callback(Database db, DBResultSet results, const char[]
if(gB_Rankings && fPoints > 0.0)
{
FormatEx(sDisplay, 128, "%T: %.03f", "WRPointsCap", client, fPoints);
menu.AddItem("-1", sDisplay);
hMenu.AddItem("-1", sDisplay);
}
// 4 - steamid3
results.FetchString(4, sAuthID, 32);
iSteamID = results.FetchInt(4);
// 5 - date
char sDate[32];
@ -1789,7 +1787,7 @@ public void SQL_SubMenu_Callback(Database db, DBResultSet results, const char[]
}
FormatEx(sDisplay, 128, "%T: %s", "WRDate", client, sDate);
menu.AddItem("-1", sDisplay);
hMenu.AddItem("-1", sDisplay);
int strafes = results.FetchInt(7);
float sync = results.FetchFloat(8);
@ -1797,25 +1795,25 @@ public void SQL_SubMenu_Callback(Database db, DBResultSet results, const char[]
if(jumps > 0 || strafes > 0)
{
FormatEx(sDisplay, 128, (sync != -1.0)? "%T: %d (%.02f%%)":"%T: %d", "WRStrafes", client, strafes, sync);
menu.AddItem("-1", sDisplay);
hMenu.AddItem("-1", sDisplay);
}
char sMenuItem[64];
FormatEx(sMenuItem, 64, "%T", "WRPlayerStats", client);
char sInfo[32];
FormatEx(sInfo, 32, "0;%s", sAuthID);
FormatEx(sInfo, 32, "0;%d", iSteamID);
if(gB_Stats)
{
menu.AddItem(sInfo, sMenuItem);
hMenu.AddItem(sInfo, sMenuItem);
}
if(CheckCommandAccess(client, "sm_delete", ADMFLAG_RCON))
{
FormatEx(sMenuItem, 64, "%T", "WRDeleteRecord", client);
FormatEx(sInfo, 32, "1;%d", id);
menu.AddItem(sInfo, sMenuItem);
hMenu.AddItem(sInfo, sMenuItem);
}
GetTrackName(client, results.FetchInt(11), sTrack, 32);
@ -1825,12 +1823,12 @@ public void SQL_SubMenu_Callback(Database db, DBResultSet results, const char[]
{
char sMenuItem[64];
FormatEx(sMenuItem, 64, "%T", "DatabaseError", client);
menu.AddItem("-1", sMenuItem);
hMenu.AddItem("-1", sMenuItem);
}
if(strlen(sName) > 0)
{
FormatEx(sFormattedTitle, 256, "%s %s\n--- %s: [%s]", sName, sAuthID, sMap, sTrack);
FormatEx(sFormattedTitle, 256, "%s [U:1:%d]\n--- %s: [%s]", sName, iSteamID, sMap, sTrack);
}
else
@ -1838,9 +1836,9 @@ public void SQL_SubMenu_Callback(Database db, DBResultSet results, const char[]
FormatEx(sFormattedTitle, 256, "%T", "Error", client);
}
menu.SetTitle(sFormattedTitle);
menu.ExitBackButton = true;
menu.Display(client, 20);
hMenu.SetTitle(sFormattedTitle);
hMenu.ExitBackButton = true;
hMenu.Display(client, 20);
}
public int SubMenu_Handler(Menu menu, MenuAction action, int param1, int param2)
@ -1861,7 +1859,7 @@ public int SubMenu_Handler(Menu menu, MenuAction action, int param1, int param2)
{
case 0:
{
Shavit_OpenStatsMenu(param1, sExploded[1]);
Shavit_OpenStatsMenu(param1, StringToInt(sExploded[1]));
}
case 1:
@ -1956,14 +1954,14 @@ void SQL_DBConnect()
if(gB_MySQL)
{
FormatEx(sQuery, 1024,
"CREATE TABLE IF NOT EXISTS `%splayertimes` (`id` INT NOT NULL AUTO_INCREMENT, `auth` VARCHAR(32), `map` VARCHAR(128), `time` FLOAT, `jumps` INT, `style` TINYINT, `date` VARCHAR(16), `strafes` INT, `sync` FLOAT, `points` FLOAT NOT NULL DEFAULT 0, `track` TINYINT NOT NULL DEFAULT 0, `perfs` FLOAT DEFAULT 0, PRIMARY KEY (`id`), INDEX `map` (`map`, `style`, `track`, `time`), INDEX `auth` (`auth`, `date`, `points`), INDEX `time` (`time`), CONSTRAINT `%spt_auth` FOREIGN KEY (`auth`) REFERENCES `%susers` (`auth`) ON UPDATE CASCADE ON DELETE CASCADE) ENGINE=INNODB;",
"CREATE TABLE IF NOT EXISTS `%splayertimes` (`id` INT NOT NULL AUTO_INCREMENT, `auth` INT, `map` VARCHAR(128), `time` FLOAT, `jumps` INT, `style` TINYINT, `date` INT, `strafes` INT, `sync` FLOAT, `points` FLOAT NOT NULL DEFAULT 0, `track` TINYINT NOT NULL DEFAULT 0, `perfs` FLOAT DEFAULT 0, PRIMARY KEY (`id`), INDEX `map` (`map`, `style`, `track`, `time`), INDEX `auth` (`auth`, `date`, `points`), INDEX `time` (`time`), CONSTRAINT `%spt_auth` FOREIGN KEY (`auth`) REFERENCES `%susers` (`auth`) ON UPDATE CASCADE ON DELETE CASCADE) ENGINE=INNODB;",
gS_MySQLPrefix, gS_MySQLPrefix, gS_MySQLPrefix);
}
else
{
FormatEx(sQuery, 1024,
"CREATE TABLE IF NOT EXISTS `%splayertimes` (`id` INTEGER PRIMARY KEY, `auth` VARCHAR(32), `map` VARCHAR(128), `time` FLOAT, `jumps` INT, `style` TINYINT, `date` VARCHAR(16), `strafes` INT, `sync` FLOAT, `points` FLOAT NOT NULL DEFAULT 0, `track` TINYINT NOT NULL DEFAULT 0, `perfs` FLOAT DEFAULT 0, CONSTRAINT `%spt_auth` FOREIGN KEY (`auth`) REFERENCES `%susers` (`auth`) ON UPDATE CASCADE ON DELETE CASCADE);",
"CREATE TABLE IF NOT EXISTS `%splayertimes` (`id` INTEGER PRIMARY KEY, `auth` INT, `map` VARCHAR(128), `time` FLOAT, `jumps` INT, `style` TINYINT, `date` INT, `strafes` INT, `sync` FLOAT, `points` FLOAT NOT NULL DEFAULT 0, `track` TINYINT NOT NULL DEFAULT 0, `perfs` FLOAT DEFAULT 0, CONSTRAINT `%spt_auth` FOREIGN KEY (`auth`) REFERENCES `%susers` (`auth`) ON UPDATE CASCADE ON DELETE CASCADE);",
gS_MySQLPrefix, gS_MySQLPrefix, gS_MySQLPrefix);
}
@ -2077,8 +2075,7 @@ public void Shavit_OnFinish(int client, int style, float time, int jumps, int st
if(iOverwrite > 0)
{
char sAuthID[32];
GetClientAuthId(client, AuthId_Steam3, sAuthID, 32);
int iSteamID = GetSteamAccountID(client);
char sQuery[512];
@ -2091,14 +2088,14 @@ public void Shavit_OnFinish(int client, int style, float time, int jumps, int st
return;
}
FormatEx(sQuery, 512, "INSERT INTO %splayertimes (auth, map, time, jumps, date, style, strafes, sync, points, track, perfs) VALUES ('%s', '%s', %f, %d, %d, %d, %d, %.2f, 0.0, %d, %.2f);", gS_MySQLPrefix, sAuthID, gS_Map, time, jumps, GetTime(), style, strafes, sync, track, perfs);
FormatEx(sQuery, 512, "INSERT INTO %splayertimes (auth, map, time, jumps, date, style, strafes, sync, points, track, perfs) VALUES (%d, '%s', %f, %d, %d, %d, %d, %.2f, 0.0, %d, %.2f);", gS_MySQLPrefix, iSteamID, gS_Map, time, jumps, GetTime(), style, strafes, sync, track, perfs);
}
else // update
{
Shavit_PrintToChatAll("%s[%s]%s %T", gS_ChatStrings.sVariable, sTrack, gS_ChatStrings.sText, "NotFirstCompletion", LANG_SERVER, gS_ChatStrings.sVariable2, client, gS_ChatStrings.sText, gS_ChatStrings.sStyle, gS_StyleStrings[style].sStyleName, gS_ChatStrings.sText, gS_ChatStrings.sVariable2, sTime, gS_ChatStrings.sText, gS_ChatStrings.sVariable, iRank, gS_ChatStrings.sText, jumps, strafes, sSync, gS_ChatStrings.sText, gS_ChatStrings.sWarning, sDifference);
FormatEx(sQuery, 512, "UPDATE %splayertimes SET time = %f, jumps = %d, date = %d, strafes = %d, sync = %.02f, points = 0.0, perfs = %.2f WHERE map = '%s' AND auth = '%s' AND style = %d AND track = %d;", gS_MySQLPrefix, time, jumps, GetTime(), strafes, sync, perfs, gS_Map, sAuthID, style, track);
FormatEx(sQuery, 512, "UPDATE %splayertimes SET time = %f, jumps = %d, date = %d, strafes = %d, sync = %.02f, points = 0.0, perfs = %.2f WHERE map = '%s' AND auth = %d AND style = %d AND track = %d;", gS_MySQLPrefix, time, jumps, GetTime(), strafes, sync, perfs, gS_Map, iSteamID, style, track);
}
gH_SQL.Query(SQL_OnFinish_Callback, sQuery, GetClientSerial(client), DBPrio_High);