#include <a_samp> #include <a_mysql> native WP_Hash(buffer[], len, const str[]); native gpci (playerid, serial [], len); #define WHITE 0xFFFFFFAA #define GREY 0xAFAFAFAA #define RED 0xFF0000AA #define YELLOW 0xFFFF00AA #define LIGHTBLUE 0x33CCFFAA #define CHAT_WHITE "{FFFFFF}" #define CHAT_GREY "{AFAFAF}" #define CHAT_RED "{FF0000}" #define CHAT_YELLOW "{FFFF00}" #define CHAT_LIGHTBLUE "{33CCFF}" forward OnPlayerDataLoaded(playerid, race_check); forward OnPlayerRegister(playerid); #define SQL_HOST "127.0.0.1" //lets leave it because this is your local host #define SQL_DB "samp" #define SQL_USER "root" #define SQL_PASS "" stock PlayerIP(playerid) { new IP[16]; GetPlayerIp(playerid, IP, sizeof(IP)); return IP; } stock PlayerName(playerid) { new pName[MAX_PLAYER_NAME]; GetPlayerName(playerid, pName, sizeof(pName)); return pName; } stock PlayerSerial(playerid) { new serial[64]; gpci(playerid,serial, sizeof(serial)); return serial; } //MySQL connection handle new g_SQL = -1; //player data enum E_PLAYERS { ID, Name[MAX_PLAYER_NAME], Password[129], Money, bool:IsLoggedIn, bool:IsRegistered, LoginAttempts, LoginTimer }; new Player[MAX_PLAYERS][E_PLAYERS]; new g_MysqlRaceCheck[MAX_PLAYERS]; //dialog data enum { DIALOG_INVALID, DIALOG_UNUSED, DIALOG_LOGIN, DIALOG_REGISTER, }; /* * SA-MP callbacks */ public OnGameModeInit() { mysql_log(LOG_ERROR | LOG_WARNING, LOG_TYPE_HTML); //logs errors and warnings into a nice .html log file g_SQL = mysql_connect(SQL_HOST, SQL_USER, SQL_DB, SQL_PASS); SetupPlayerTable(); return 1; } public OnGameModeExit() { //save all player data before closing connection for(new p=0; p < MAX_PLAYERS; ++p) if(IsPlayerConnected(p)) UpdatePlayerData(p); mysql_close(); return 1; } public OnPlayerConnect(playerid) { g_MysqlRaceCheck[playerid]++; //reset player data for(new E_PLAYERS:e; e < E_PLAYERS; ++e) Player[playerid][e] = 0; new query[128]; GetPlayerName(playerid, Player[playerid][Name], MAX_PLAYER_NAME); //send a query to recieve all the stored player data from the table mysql_format(g_SQL, query, sizeof(query), "SELECT * FROM `players` WHERE `username` = '%e' LIMIT 1", Player[playerid][Name]); mysql_tquery(g_SQL, query, "OnPlayerDataLoaded", "dd", playerid, g_MysqlRaceCheck[playerid]); return 1; } public OnPlayerDataLoaded(playerid, race_check) { /* race condition check: player A connects -> SELECT query is fired -> this query takes very long while the query is still processing, player A with playerid 2 disconnects player B joins now with playerid 2 -> our laggy SELECT query is finally finished, but for the wrong player what do we do against it? we create a connection count for each playerid and increase it everytime the playerid connects or disconnects we also pass the current value of the connection count to our OnPlayerDataLoaded callback then we check if current connection count is the same as connection count we passed to the callback if yes, everything is okay, if not, we just kick the player */ if(race_check != g_MysqlRaceCheck[playerid]) return Kick(playerid); new string[128]; if(cache_num_rows() > 0) { AssignPlayerData(playerid); format(string, sizeof(string), CHAT_WHITE "This account (" CHAT_YELLOW "%s" CHAT_WHITE ") is registered. Please login by entering your password in the field below:", Player[playerid][Name]); ShowPlayerDialog(playerid, DIALOG_LOGIN, DIALOG_STYLE_PASSWORD, "Login", string, "Login", "Abort"); Player[playerid][IsRegistered] = true; } else { format(string, sizeof(string), CHAT_WHITE "Welcome " CHAT_YELLOW "%s" CHAT_WHITE ", you can register by entering your password in the field below:", Player[playerid][Name]); ShowPlayerDialog(playerid, DIALOG_REGISTER, DIALOG_STYLE_PASSWORD, "Registration", string, "Register", "Abort"); Player[playerid][IsRegistered] = false; } return 1; } public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[]) { if(dialogid == DIALOG_INVALID || dialogid == DIALOG_UNUSED) return 1; switch(dialogid) { case DIALOG_LOGIN: { if(!response) return Kick(playerid); if(strlen(inputtext) <= 5) return ShowPlayerDialog(playerid, DIALOG_LOGIN, DIALOG_STYLE_PASSWORD, "Login", CHAT_RED "Your password must be longer than 5 characters!\n" CHAT_WHITE "Please enter your password in the field below:", "Login", "Abort"); new hashed_pass[129]; WP_Hash(hashed_pass, sizeof(hashed_pass), inputtext); if(strcmp(hashed_pass, Player[playerid][Password]) == 0) { //correct password, spawn the player ShowPlayerDialog(playerid, DIALOG_UNUSED, DIALOG_STYLE_MSGBOX, "Login", "You have been successfully logged in.", "Okay", ""); Player[playerid][IsLoggedIn] = true; SetSpawnInfo(playerid, 0, 0, 0.0, 0.0, 0.0, 0.0, 0, 0, 0, 0, 0, 0); SpawnPlayer(playerid); } else { Player[playerid][LoginAttempts]++; if(Player[playerid][LoginAttempts] >= 3) { ShowPlayerDialog(playerid, DIALOG_UNUSED, DIALOG_STYLE_MSGBOX, "Login", CHAT_RED "You have mistyped your password too often (3 times).", "Okay", ""); DelayedKick(playerid); } else ShowPlayerDialog(playerid, DIALOG_LOGIN, DIALOG_STYLE_PASSWORD, "Login", CHAT_RED "Wrong password!\n" CHAT_WHITE "Please enter your password in the field below:", "Login", "Abort"); } } case DIALOG_REGISTER: { if(!response) return Kick(playerid); if(strlen(inputtext) <= 5) return ShowPlayerDialog(playerid, DIALOG_REGISTER, DIALOG_STYLE_PASSWORD, "Registration", CHAT_RED "Your password must be longer than 5 characters!\n" CHAT_WHITE "Please enter your password in the field below:", "Register", "Abort"); new query[256]; WP_Hash(Player[playerid][Password], 129, inputtext); mysql_format(g_SQL, query, sizeof(query), "INSERT INTO `players` (`username`, `password`, `IP`, `serial`]) VALUES ('%e', '%s', '%s','%S')", Player[playerid][Name], Player[playerid][Password], PlayerIP(playerid), PlayerSerial(playerid)); mysql_tquery(g_SQL, query, "OnPlayerRegister", "d", playerid); } default: return 0; } return 1; } public OnPlayerRegister(playerid) { Player[playerid][ID] = cache_insert_id(); ShowPlayerDialog(playerid, DIALOG_UNUSED, DIALOG_STYLE_MSGBOX, "Registration", "Account successfully registered, you have been automatically logged in.", "Okay", ""); Player[playerid][IsLoggedIn] = true; Player[playerid][IsRegistered] = true; SetSpawnInfo(playerid, 0, 0, 0.0, 0.0, 0.0, 0.0, 0, 0, 0, 0, 0, 0); SpawnPlayer(playerid); return 1; } public OnPlayerSpawn(playerid) { ResetPlayerMoney(playerid); GivePlayerMoney(playerid, Player[playerid][Money]); return 1; } public OnPlayerDisconnect(playerid,reason) { g_MysqlRaceCheck[playerid]++; UpdatePlayerData(playerid); return 1; } /* * functions */ AssignPlayerData(playerid) { Player[playerid][ID] = cache_get_field_content_int(0, "id"); cache_get_field_content(0, "password", Player[playerid][Password], g_SQL, 129); Player[playerid][Money] = cache_get_field_content_int(0, "money"); return 1; } UpdatePlayerData(playerid) { if(Player[playerid][IsLoggedIn] == false) return 0; new query[128]; mysql_format(g_SQL, query, sizeof(query), "UPDATE `players` SET `money` = '%d' WHERE `username` = '%e' LIMIT 1", Player[playerid][Money], Player[playerid][Name]);// mysql_tquery(g_SQL, query); return 1; } SetupPlayerTable() { mysql_query(g_SQL, "CREATE TABLE IF NOT EXISTS `players` (`id` int(11) NOT NULL auto_increment PRIMARY KEY,`username` varchar(30) NOT NULL,`password` varchar(130) NOT NULL,`money` int(10) NOT NULL default '0', `IP` varchar(16) NOT NULL), `serial` varchar(64) NOT NULL)", false); return 1; } DelayedKick(playerid, time=500) { SetTimerEx("_KickPlayerDelayed", time, false, "d", playerid); return 1; } forward _KickPlayerDelayed(playerid); public _KickPlayerDelayed(playerid) { Kick(playerid); return 1; } main() {}
#include <a_samp> #include <a_mysql> #include <crashdetect> native WP_Hash(buffer[], len, const str[]); native gpci (playerid, serial [], len); #define WHITE 0xFFFFFFAA #define GREY 0xAFAFAFAA #define RED 0xFF0000AA #define YELLOW 0xFFFF00AA #define LIGHTBLUE 0x33CCFFAA #define CHAT_WHITE "{FFFFFF}" #define CHAT_GREY "{AFAFAF}" #define CHAT_RED "{FF0000}" #define CHAT_YELLOW "{FFFF00}" #define CHAT_LIGHTBLUE "{33CCFF}" forward OnPlayerDataLoaded(playerid, race_check); forward OnPlayerRegister(playerid); #define SQL_HOST "127.0.0.1" //lets leave it because this is your local host #define SQL_DB "samp" #define SQL_USER "root" #define SQL_PASS "" stock PlayerIP(playerid) { new IP[16]; GetPlayerIp(playerid, IP, sizeof(IP)); return IP; } stock PlayerName(playerid) { new pName[MAX_PLAYER_NAME]; GetPlayerName(playerid, pName, sizeof(pName)); return pName; } stock PlayerSerial(playerid) { new serial[64]; gpci(playerid,serial, sizeof(serial)); return serial; } //MySQL connection handle new g_SQL = -1; //player data enum E_PLAYERS { ID, Name[MAX_PLAYER_NAME], Password[129], Money, bool:IsLoggedIn, bool:IsRegistered, LoginAttempts, LoginTimer }; new Player[MAX_PLAYERS][E_PLAYERS]; new g_MysqlRaceCheck[MAX_PLAYERS]; //dialog data enum { DIALOG_INVALID, DIALOG_UNUSED, DIALOG_LOGIN, DIALOG_REGISTER, }; /* * SA-MP callbacks */ public OnGameModeInit() { AddPlayerClass(1, 1958.33, 1343.12, 15.36, 269.15, 26, 36, 28, 150, 0, 0); mysql_log(LOG_ERROR | LOG_WARNING, LOG_TYPE_HTML); //logs errors and warnings into a nice .html log file g_SQL = mysql_connect(SQL_HOST, SQL_USER, SQL_DB, SQL_PASS); SetupPlayerTable(); return 1; } public OnGameModeExit() { //save all player data before closing connection for(new p=0; p < MAX_PLAYERS; ++p) if(IsPlayerConnected(p)) UpdatePlayerData(p); mysql_close(); return 1; } public OnPlayerConnect(playerid) { g_MysqlRaceCheck[playerid]++; //reset player data for(new E_PLAYERS:e; e < E_PLAYERS; ++e) Player[playerid][e] = 0; new query[128]; GetPlayerName(playerid, Player[playerid][Name], MAX_PLAYER_NAME); //send a query to recieve all the stored player data from the table mysql_format(g_SQL, query, sizeof(query), "SELECT * FROM `players` WHERE `username` = '%e' LIMIT 1", Player[playerid][Name]); mysql_tquery(g_SQL, query, "OnPlayerDataLoaded", "dd", playerid, g_MysqlRaceCheck[playerid]); return 1; } public OnPlayerDataLoaded(playerid, race_check) { /* race condition check: player A connects -> SELECT query is fired -> this query takes very long while the query is still processing, player A with playerid 2 disconnects player B joins now with playerid 2 -> our laggy SELECT query is finally finished, but for the wrong player what do we do against it? we create a connection count for each playerid and increase it everytime the playerid connects or disconnects we also pass the current value of the connection count to our OnPlayerDataLoaded callback then we check if current connection count is the same as connection count we passed to the callback if yes, everything is okay, if not, we just kick the player */ if(race_check != g_MysqlRaceCheck[playerid]) return Kick(playerid); new string[128]; if(cache_num_rows() > 0) { AssignPlayerData(playerid); format(string, sizeof(string), CHAT_WHITE "This account (" CHAT_YELLOW "%s" CHAT_WHITE ") is registered. Please login by entering your password in the field below:", Player[playerid][Name]); ShowPlayerDialog(playerid, DIALOG_LOGIN, DIALOG_STYLE_PASSWORD, "Login", string, "Login", "Abort"); Player[playerid][IsRegistered] = true; } else { format(string, sizeof(string), CHAT_WHITE "Welcome " CHAT_YELLOW "%s" CHAT_WHITE ", you can register by entering your password in the field below:", Player[playerid][Name]); ShowPlayerDialog(playerid, DIALOG_REGISTER, DIALOG_STYLE_PASSWORD, "Registration", string, "Register", "Abort"); Player[playerid][IsRegistered] = false; } return 1; } public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[]) { if(dialogid == DIALOG_INVALID || dialogid == DIALOG_UNUSED) return 1; switch(dialogid) { case DIALOG_LOGIN: { if(!response) return Kick(playerid); if(strlen(inputtext) <= 5) return ShowPlayerDialog(playerid, DIALOG_LOGIN, DIALOG_STYLE_PASSWORD, "Login", CHAT_RED "Your password must be longer than 5 characters!\n" CHAT_WHITE "Please enter your password in the field below:", "Login", "Abort"); new hashed_pass[129]; WP_Hash(hashed_pass, sizeof(hashed_pass), inputtext); if(strcmp(hashed_pass, Player[playerid][Password]) == 0) { //correct password, spawn the player ShowPlayerDialog(playerid, DIALOG_UNUSED, DIALOG_STYLE_MSGBOX, "Login", "You have been successfully logged in.", "Okay", ""); Player[playerid][IsLoggedIn] = true; SetSpawnInfo(playerid, 0, 0, 0.0, 0.0, 0.0, 0.0, 0, 0, 0, 0, 0, 0); SpawnPlayer(playerid); } else { Player[playerid][LoginAttempts]++; if(Player[playerid][LoginAttempts] >= 3) { ShowPlayerDialog(playerid, DIALOG_UNUSED, DIALOG_STYLE_MSGBOX, "Login", CHAT_RED "You have mistyped your password too often (3 times).", "Okay", ""); DelayedKick(playerid); } else ShowPlayerDialog(playerid, DIALOG_LOGIN, DIALOG_STYLE_PASSWORD, "Login", CHAT_RED "Wrong password!\n" CHAT_WHITE "Please enter your password in the field below:", "Login", "Abort"); } } case DIALOG_REGISTER: { if(!response) return Kick(playerid); if(strlen(inputtext) <= 5) return ShowPlayerDialog(playerid, DIALOG_REGISTER, DIALOG_STYLE_PASSWORD, "Registration", CHAT_RED "Your password must be longer than 5 characters!\n" CHAT_WHITE "Please enter your password in the field below:", "Register", "Abort"); new query[256]; WP_Hash(Player[playerid][Password], 129, inputtext); mysql_format(g_SQL, query, sizeof(query), "INSERT INTO `players` (`username`, `password`, `IP`, `serial`) VALUES ('%e', '%s', '%s','%s')", Player[playerid][Name], Player[playerid][Password], PlayerIP(playerid), PlayerSerial(playerid)); //mysql_format(g_SQL, query, sizeof(query), "INSERT INTO `players` (`username`, `password`, `IP`) VALUES ('%e', '%s', '%s')", Player[playerid][Name], Player[playerid][Password], PlayerIP(playerid)); mysql_tquery(g_SQL, query, "OnPlayerRegister", "d", playerid); } default: return 0; } return 1; } public OnPlayerRegister(playerid) { Player[playerid][ID] = cache_insert_id(); ShowPlayerDialog(playerid, DIALOG_UNUSED, DIALOG_STYLE_MSGBOX, "Registration", "Account successfully registered, you have been automatically logged in.", "Okay", ""); Player[playerid][IsLoggedIn] = true; Player[playerid][IsRegistered] = true; SetSpawnInfo(playerid, 0, 0, 0.0, 0.0, 0.0, 0.0, 0, 0, 0, 0, 0, 0); SpawnPlayer(playerid); return 1; } public OnPlayerSpawn(playerid) { ResetPlayerMoney(playerid); GivePlayerMoney(playerid, Player[playerid][Money]); return 1; } public OnPlayerDisconnect(playerid,reason) { g_MysqlRaceCheck[playerid]++; UpdatePlayerData(playerid); return 1; } /* * functions */ AssignPlayerData(playerid) { Player[playerid][ID] = cache_get_field_content_int(0, "id"); cache_get_field_content(0, "password", Player[playerid][Password], g_SQL, 129); Player[playerid][Money] = cache_get_field_content_int(0, "money"); return 1; } UpdatePlayerData(playerid) { if(Player[playerid][IsLoggedIn] == false) return 0; new query[128]; mysql_format(g_SQL, query, sizeof(query), "UPDATE `players` SET `money` = '%d' WHERE `username` = '%e' LIMIT 1", Player[playerid][Money], Player[playerid][Name]);// mysql_tquery(g_SQL, query); return 1; } SetupPlayerTable() { mysql_query(g_SQL, "CREATE TABLE IF NOT EXISTS `players` (`id` int(11) NOT NULL auto_increment PRIMARY KEY,`username` varchar(30) NOT NULL,`password` varchar(130) NOT NULL,`money` int(10) NOT NULL default '0', `IP` varchar(16) NOT NULL, `serial` varchar(64) NOT NULL)", false); return 1; } DelayedKick(playerid, time=500) { SetTimerEx("_KickPlayerDelayed", time, false, "d", playerid); return 1; } forward _KickPlayerDelayed(playerid); public _KickPlayerDelayed(playerid) { Kick(playerid); return 1; } main() {}
Gpci doesn't work as you think it works, it's not intended to be a function which gives you an unique ID for each individual player.
|
Originally Posted by Kalcor
It is not an SHA1. The fact that you think it is makes me think you are connected to some cheater/bot websites, which is exactly why the function exists and why it's not (and will never be) documented.
Here is all anyone needs to know about gpci: - It is a non-reversible (lossy) hash derived from information about your San Andreas installation path. - It is not a unique ID. - It was added to assist owners of large servers who deal with constant attacks from cheaters and botters. - It has been in SA-MP for 2 years. |
I am now derailing the topic a bit, and while there may be problems in your SQL syntax, you should NOT use Gpci for that purpose. Here's why:
Stick to range-banning the last 3 digits of IP (example: 192.168.1.***). |