Here's a test case plugin I made to demonstrate what I meant.
PHP Code:
#pragma semicolon 1
#include <sourcemod>
new g_iRowId[MAXPLAYERS+1];
new g_iUserId[MAXPLAYERS+1];
new Handle:g_hDatabase;
public OnPluginStart() {
HookEvent("player_disconnect", Event_Disconnect);
}
public OnMapStart() {
if (g_hDatabase == INVALID_HANDLE) {
SQL_TConnect(SQL_Connected);
}
}
public SQL_Connected(Handle:hOwner, Handle:hHndl, const String:szError[], any:data) {
if (hHndl == INVALID_HANDLE) {
SetFailState("Database failure: %s", szError);
} else {
g_hDatabase = hHndl;
}
SQL_SetCharset(g_hDatabase, "utf8");
SQL_CreateTables();
}
public OnClientConnected(iClient) {
if (iClient && !IsFakeClient(iClient) && !GetClientOfUserId(g_iUserId[iClient])) {
g_iRowId[iClient] = 0;
}
g_iUserId[iClient] = 0;
}
public OnClientAuthorized(iClient, const String:szAuth[]) {
if (iClient && !IsFakeClient(iClient) && !g_iRowId[iClient]) {
decl String:szClientName[32], String:szSafeName[65];
GetClientName(iClient, szClientName, sizeof(szClientName));
SQL_EscapeString(g_hDatabase, szClientName, szSafeName, sizeof(szSafeName));
decl String:szQuery[512];
Format(szQuery, sizeof(szQuery), "INSERT INTO test_userids (auth, name) VALUES ('%s', '%s')", szAuth, szSafeName);
SQL_TQuery(g_hDatabase, SQL_PlayerConnected, szQuery, GetClientSerial(iClient));
}
}
public SQL_PlayerConnected(Handle:hOwner, Handle:hHndl, const String:szError[], any:iSerial) {
new iClient = GetClientFromSerial(iSerial);
if (iClient) {
g_iRowId[iClient] = SQL_GetInsertId(hHndl);
g_iUserId[iClient] = GetClientUserId(iClient);
}
}
public Event_Disconnect(Handle:hEvent, const String:szEventName[], bool:bDontBroadcast) {
new iUserId = GetEventInt(hEvent, "userid"), iClient = GetClientOfUserId(iUserId);
if (iClient) {
if (!IsFakeClient(iClient) && g_iRowId[iClient]) {
decl String:szQuery[512];
Format(szQuery, sizeof(szQuery), "UPDATE test_userids SET disconnect_time = CURRENT_TIMESTAMP WHERE id = %i", g_iRowId[iClient]);
SQL_SendQuery(szQuery);
}
} else {
for (new i = 1; i <= MaxClients; i++) {
if (g_iUserId[i] && g_iUserId[i] == iUserId) {
decl String:szQuery[512];
Format(szQuery, sizeof(szQuery), "UPDATE test_userids SET disconnect_time = CURRENT_TIMESTAMP WHERE id = %i", g_iRowId[i]);
SQL_SendQuery(szQuery);
break;
}
}
}
}
SQL_SendQuery(const String:szQuery[]) {
new Handle:hData = CreateDataPack();
WritePackString(hData, szQuery);
SQL_TQuery(g_hDatabase, SQL_QuerySent, szQuery, hData);
}
public SQL_QuerySent(Handle:hOwner, Handle:hHndl, const String:szError[], any:hData) {
ResetPack(hData);
decl String:szQuery[512];
ReadPackString(hData, szQuery, sizeof(szQuery));
CloseHandle(hData);
if (hHndl == INVALID_HANDLE) {
LogError("Query Failed! %s", szError);
LogError("Query: %s", szQuery);
}
}
SQL_CreateTables() {
SQL_SendQuery("\
CREATE TABLE IF NOT EXISTS `test_userids` ( \
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, \
`auth` VARCHAR(22) NOT NULL, \
`name` VARCHAR(32) NOT NULL, \
`connect_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, \
`disconnect_time` TIMESTAMP NULL, \
PRIMARY KEY (`id`) \
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;");
}
Here's an example of the output:
1: Connecting and then disconnecting
2: Connecting, map change, disconnected after loading
3: Connecting, map change, disconnected while loading (time updates to after the server finishes loading and the event is fired)
4: Reconnecting again