From 3d0cd963195e55e836e71028b28c469d5e4fff0a Mon Sep 17 00:00:00 2001 From: olivia Date: Mon, 14 Apr 2025 10:52:36 -0700 Subject: [PATCH] Add FirstLogin to database and profile (#1234) fix FirstLogin query for sqlite fix statsmenu query oopsie teehee :3 sql-create-tables-and-migrations.sp - fix queries for sqlite Simplify firstlogin column initialization --- .../sql-create-tables-and-migrations.sp | 21 +++++++++++++++++-- addons/sourcemod/scripting/shavit-core.sp | 8 +++---- addons/sourcemod/scripting/shavit-stats.sp | 21 ++++++++++++------- .../translations/shavit-stats.phrases.txt | 4 ++++ 4 files changed, 40 insertions(+), 14 deletions(-) diff --git a/addons/sourcemod/scripting/include/shavit/sql-create-tables-and-migrations.sp b/addons/sourcemod/scripting/include/shavit/sql-create-tables-and-migrations.sp index b9e64ef8..0d1d9e95 100644 --- a/addons/sourcemod/scripting/include/shavit/sql-create-tables-and-migrations.sp +++ b/addons/sourcemod/scripting/include/shavit/sql-create-tables-and-migrations.sp @@ -53,6 +53,7 @@ enum Migration_DeprecateExactTimeInt, Migration_AddPlayertimesAuthFK, Migration_FixSQLiteMapzonesROWID, + Migration_AddUsersFirstLogin, MIGRATIONS_END }; @@ -87,6 +88,7 @@ char gS_MigrationNames[][] = { "DeprecateExactTimeInt", "AddPlayertimesAuthFK", "FixSQLiteMapzonesROWID", + "AddUsersFirstLogin", }; static Database gH_SQL; @@ -133,13 +135,13 @@ public void SQL_CreateTables(Database hSQL, const char[] prefix, int driver) if (driver == Driver_mysql) { FormatEx(sQuery, sizeof(sQuery), - "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, `playtime` FLOAT NOT NULL DEFAULT 0, PRIMARY KEY (`auth`), INDEX `points` (`points`), INDEX `lastlogin` (`lastlogin`)) ENGINE=INNODB;", + "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, `firstlogin` INT NOT NULL DEFAULT -1, `points` FLOAT NOT NULL DEFAULT 0, `playtime` FLOAT NOT NULL DEFAULT 0, PRIMARY KEY (`auth`), INDEX `points` (`points`), INDEX `lastlogin` (`lastlogin`)) ENGINE=INNODB;", gS_SQLPrefix); } else { FormatEx(sQuery, sizeof(sQuery), - "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, `playtime` FLOAT NOT NULL DEFAULT 0);", + "CREATE TABLE IF NOT EXISTS `%susers` (`auth` INT NOT NULL PRIMARY KEY, `name` VARCHAR(32), `ip` INT, `lastlogin` INTEGER NOT NULL DEFAULT -1, `firstlogin` INTEGER NOT NULL DEFAULT -1, `points` FLOAT NOT NULL DEFAULT 0, `playtime` FLOAT NOT NULL DEFAULT 0);", gS_SQLPrefix); } @@ -369,6 +371,7 @@ void ApplyMigration(int migration) case Migration_DeprecateExactTimeInt: ApplyMigration_DeprecateExactTimeInt(); case Migration_AddPlayertimesAuthFK: ApplyMigration_AddPlayertimesAuthFK(); case Migration_FixSQLiteMapzonesROWID: ApplyMigration_FixSQLiteMapzonesROWID(); + case Migration_AddUsersFirstLogin: ApplyMigration_AddUsersFirstLogin(); } } @@ -686,6 +689,20 @@ public void Trans_FixSQLiteMapzonesROWID_Error(Database db, any data, int numQue LogError("Timer error! SQLiteMapzonesROWID migration transaction failed. Reason: %s", error); } +void ApplyMigration_AddUsersFirstLogin() +{ + char sQuery[256]; + FormatEx(sQuery, sizeof(sQuery), "ALTER TABLE %susers ADD `firstlogin` INT NOT NULL DEFAULT -1 %s;", gS_SQLPrefix, (gI_Driver == Driver_mysql) ? "AFTER `lastlogin`" : ""); + QueryLog(gH_SQL, ApplyMigration_AddUsersFirstLogin2222222_Callback, sQuery, Migration_AddUsersFirstLogin, DBPrio_High); +} + +public void ApplyMigration_AddUsersFirstLogin2222222_Callback(Database db, DBResultSet results, const char[] error, any data) +{ + char sQuery[256]; + FormatEx(sQuery, sizeof(sQuery), "UPDATE %susers SET firstlogin = lastlogin WHERE lastlogin > 0;", gS_SQLPrefix); + QueryLog(gH_SQL, SQL_TableMigrationSingleQuery_Callback, sQuery, Migration_AddUsersFirstLogin, DBPrio_High); +} + public void SQL_TableMigrationSingleQuery_Callback(Database db, DBResultSet results, const char[] error, any data) { InsertMigration(data); diff --git a/addons/sourcemod/scripting/shavit-core.sp b/addons/sourcemod/scripting/shavit-core.sp index 25fb4c01..2d74994e 100644 --- a/addons/sourcemod/scripting/shavit-core.sp +++ b/addons/sourcemod/scripting/shavit-core.sp @@ -2807,14 +2807,14 @@ public void OnClientAuthorized(int client, const char[] auth) if (gI_Driver == Driver_mysql) { 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); + "INSERT INTO %susers (auth, name, ip, lastlogin, firstlogin) VALUES (%d, '%s', %d, %d, %d) ON DUPLICATE KEY UPDATE name = '%s', ip = %d, lastlogin = %d;", + gS_MySQLPrefix, iSteamID, sEscapedName, iIPAddress, iTime, iTime, sEscapedName, iIPAddress, iTime); } else // postgresql & sqlite { FormatEx(sQuery, 512, - "INSERT INTO %susers (auth, name, ip, lastlogin) VALUES (%d, '%s', %d, %d) ON CONFLICT(auth) DO UPDATE SET name = '%s', ip = %d, lastlogin = %d;", - gS_MySQLPrefix, iSteamID, sEscapedName, iIPAddress, iTime, sEscapedName, iIPAddress, iTime); + "INSERT INTO %susers (auth, name, ip, lastlogin, firstlogin) VALUES (%d, '%s', %d, %d, %d) ON CONFLICT(auth) DO UPDATE SET name = '%s', ip = %d, lastlogin = %d;", + gS_MySQLPrefix, iSteamID, sEscapedName, iIPAddress, iTime, iTime, sEscapedName, iIPAddress, iTime); } QueryLog(gH_SQL, SQL_InsertUser_Callback, sQuery, GetClientSerial(client)); diff --git a/addons/sourcemod/scripting/shavit-stats.sp b/addons/sourcemod/scripting/shavit-stats.sp index a67ef72f..b8c622e6 100644 --- a/addons/sourcemod/scripting/shavit-stats.sp +++ b/addons/sourcemod/scripting/shavit-stats.sp @@ -890,9 +890,9 @@ Action OpenStatsMenu_Main(int steamid, int style, DataPack data) char sQuery[2048]; FormatEx(sQuery, sizeof(sQuery), - "SELECT 0, points, lastlogin, ip, playtime, name FROM %susers WHERE auth = %d\n" ... - "UNION ALL SELECT 1, SUM(playtime), 0, 0, 0, '' FROM %sstyleplaytime WHERE auth = %d AND style = %d\n" ... - "UNION ALL SELECT 2, COUNT(*), 0, 0, 0, '' FROM %susers u1\n" ... + "SELECT 0, points, lastlogin, firstlogin, ip, playtime, name FROM %susers WHERE auth = %d\n" ... + "UNION ALL SELECT 1, SUM(playtime), 0, 0, 0, 0, '' FROM %sstyleplaytime WHERE auth = %d AND style = %d\n" ... + "UNION ALL SELECT 2, COUNT(*), 0, 0, 0, 0, '' FROM %susers u1\n" ... " JOIN (SELECT points FROM %susers WHERE auth = %d) u2\n" ... " WHERE u1.points >= u2.points", gS_MySQLPrefix, steamid, @@ -960,6 +960,7 @@ public void OpenStatsMenuCallback(Database db, DBResultSet results, const char[] float fPoints; char sLastLogin[32]; + char sFirstLogin[32]; char sCountry[64]; char sPlaytime[16]; @@ -989,7 +990,11 @@ public void OpenStatsMenuCallback(Database db, DBResultSet results, const char[] FormatTime(sLastLogin, 32, "%Y-%m-%d %H:%M:%S", iLastLogin); Format(sLastLogin, 32, "%T: %s", "LastLogin", client, (iLastLogin != -1)? sLastLogin:"N/A"); - int iIPAddress = results.FetchInt(3); + int iFirstLogin = results.FetchInt(3); + FormatTime(sFirstLogin, 32, "%Y-%m-%d %H:%M:%S", iFirstLogin); + Format(sFirstLogin, 32, "%T: %s", "FirstLogin", client, (iFirstLogin != -1)? sFirstLogin:"N/A"); + + int iIPAddress = results.FetchInt(4); char sIPAddress[32]; IPAddressToString(iIPAddress, sIPAddress, 32); @@ -998,10 +1003,10 @@ public void OpenStatsMenuCallback(Database db, DBResultSet results, const char[] sCountry = "Local Area Network"; } - float fPlaytime = results.FetchFloat(4); + float fPlaytime = results.FetchFloat(5); FormatSeconds(fPlaytime, sPlaytime, sizeof(sPlaytime), false, true, true); - results.FetchString(5, gS_TargetName[client], MAX_NAME_LENGTH); + results.FetchString(6, gS_TargetName[client], MAX_NAME_LENGTH); ReplaceString(gS_TargetName[client], MAX_NAME_LENGTH, "#", "?"); } else if (type == 1) @@ -1056,8 +1061,8 @@ public void OpenStatsMenuCallback(Database db, DBResultSet results, const char[] } Menu menu = new Menu(MenuHandler_ProfileHandler); - menu.SetTitle("%s's %T. [U:1:%u]\n%T: %s\n%s\n%s\n%T: %s\n", - gS_TargetName[client], "Profile", client, gI_TargetSteamID[client], "Country", client, sCountry, sLastLogin, + menu.SetTitle("%s's %T. [U:1:%u]\n%T: %s\n%s\n%s\n%s\n%T: %s\n", + gS_TargetName[client], "Profile", client, gI_TargetSteamID[client], "Country", client, sCountry, sFirstLogin, sLastLogin, sRankingString, "Playtime", client, sPlaytime); int[] styles = new int[gI_Styles]; diff --git a/addons/sourcemod/translations/shavit-stats.phrases.txt b/addons/sourcemod/translations/shavit-stats.phrases.txt index c20c0cdb..c0c0f749 100644 --- a/addons/sourcemod/translations/shavit-stats.phrases.txt +++ b/addons/sourcemod/translations/shavit-stats.phrases.txt @@ -74,6 +74,10 @@ { "en" "Last Login" } + "FirstLogin" + { + "en" "First Login" + } "MapCompletions" { "en" "Map completions"