Advertisement
Guest User

Variable's MySQL R41-2 Registration System

a guest
Jan 29th, 2017
3,662
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Pawn 11.88 KB | None | 0 0
  1. #include <a_samp>
  2. #include <a_mysql>
  3. #include <foreach>
  4.  
  5. //Configuring MySQL Stuff to set up the connection
  6.  
  7. #define MYSQL_HOST        "Your DB Host" // Change this to your MySQL Remote IP or "localhost".
  8. #define MYSQL_USER        "Your DB User" // Change this to your MySQL Database username.
  9. #define MYSQL_PASS        "Your DB Pass" // Change this to your MySQL Database password.
  10. #define MYSQL_DATABASE    "Your DB Name" // Change this to your MySQL Database name.
  11.  
  12. // Well, don't just enter random information and expect it to work, information
  13. // Should be valid and working fine.
  14.  
  15. #define DIALOG_REGISTER        (0)
  16. #define DIALOG_LOGIN           (1)
  17.  
  18. // Make sure the dialog IDs above do not match any dialog ID you're using in your
  19. // gamemode otherwise they won't do their job properly.
  20.  
  21. new MySQL: Database, Corrupt_Check[MAX_PLAYERS];
  22.  
  23. //Creating an enumerator to store player's data for further use (below).
  24.  
  25. //==============================================================================
  26.  
  27. enum ENUM_PLAYER_DATA
  28. {
  29.     ID,
  30.     Name[25],
  31.    
  32.     Password[65],
  33.     Salt[11],
  34.    
  35.     PasswordFails,
  36.    
  37.     Kills,
  38.     Deaths,
  39.    
  40.     Score,
  41.     Cash,
  42.    
  43.     Cache: Player_Cache,
  44.     bool:LoggedIn
  45. }
  46.  
  47. new pInfo[MAX_PLAYERS][ENUM_PLAYER_DATA];
  48.  
  49. //==============================================================================
  50.  
  51. public OnGameModeInit()
  52. {
  53.     new MySQLOpt: option_id = mysql_init_options();
  54.     mysql_set_option(option_id, AUTO_RECONNECT, true); // We will set that option to automatically reconnect on timeouts.
  55.  
  56.     Database = mysql_connect(MYSQL_HOST, MYSQL_USER, MYSQL_PASS, MYSQL_DATABASE, option_id); // Setting up the "Database" handle on the given MySQL details above.
  57.  
  58.     if(Database == MYSQL_INVALID_HANDLE || mysql_errno(Database) != 0) // Checking if the database connection is invalid to shutdown.
  59.     {
  60.         print("I couldn't connect to the MySQL server, closing."); // Printing a message to the log.
  61.  
  62.         SendRconCommand("exit"); // Sending console command to shut down server.
  63.         return 1;
  64.     }
  65.  
  66.     print("I have connected to the MySQL server."); // If the given MySQL details were all okay, this message prints to the log.
  67.  
  68.     // Now, we will set up the information table of the player's information.
  69.    
  70.     mysql_tquery(Database, "CREATE TABLE IF NOT EXISTS `PLAYERS` (`ID` int(11) NOT NULL AUTO_INCREMENT,`USERNAME` varchar(24) NOT NULL,`PASSWORD` char(65) NOT NULL,`SALT` char(11) NOT NULL,`SCORE` mediumint(7), `KILLS` mediumint(7), `CASH` mediumint(7) NOT NULL DEFAULT '0',`DEATHS` mediumint(7) NOT NULL DEFAULT '0', PRIMARY KEY (`ID`), UNIQUE KEY `USERNAME` (`USERNAME`))");
  71.  
  72.     // So, this code is probably the only one which you haven't understood.
  73.     // Well, we firstly create a table only if not existing in the database which is "USERS".
  74.     // We create "ID" and set it as a primary key with auto increment to use it in retrieving information and many more uses.
  75.     // We create "USERNAME" and set it as a unique key, the USERNAME stores every player's name in the database so you can
  76.     // Control the players in offline mode and when a player leaves everything storted like kills, deaths, password and Saltion key
  77.     // Wouldn't be lost upon server's close or player's disconnection.
  78.     // We store kills, deaths, score and cash as written above so they might be useful for further use.
  79.    
  80.     return 1;
  81. }
  82.  
  83. public OnGameModeExit()
  84. {
  85.     foreach(new i: Player)
  86.     {
  87.         if(IsPlayerConnected(i)) // Checking if the players stored in "i" are connected.
  88.         {
  89.             OnPlayerDisconnect(i, 1); // We do that so players wouldn't lose their data upon server's close.
  90.         }
  91.     }
  92.  
  93.     mysql_close(Database); // Closing the database.
  94.     return 1;
  95. }
  96.    
  97. public OnPlayerConnect(playerid)
  98. {
  99.     new DB_Query[115];
  100.  
  101.     //Resetting player information.
  102.     pInfo[playerid][Kills] = 0;
  103.     pInfo[playerid][Deaths] = 0;
  104.     pInfo[playerid][PasswordFails] = 0;
  105.  
  106.     GetPlayerName(playerid, pInfo[playerid][Name], MAX_PLAYER_NAME); // Getting the player's name.
  107.     Corrupt_Check[playerid]++;
  108.    
  109.     mysql_format(Database, DB_Query, sizeof(DB_Query), "SELECT * FROM `PLAYERS` WHERE `USERNAME` = '%e' LIMIT 1", pInfo[playerid][Name]);
  110.     mysql_tquery(Database, DB_Query, "OnPlayerDataCheck", "ii", playerid, Corrupt_Check[playerid]);
  111.     return 1;
  112. }
  113.  
  114. public OnPlayerDisconnect(playerid, reason)
  115. {
  116.     Corrupt_Check[playerid]++;
  117.  
  118.     new DB_Query[256];
  119.     //Running a query to save the player's data using the stored stuff.
  120.     mysql_format(Database, DB_Query, sizeof(DB_Query), "UPDATE `PLAYERS` SET `SCORE` = %d, `CASH` = %d, `KILLS` = %d, `DEATHS` = %d WHERE `ID` = %d LIMIT 1",
  121.     pInfo[playerid][Score], pInfo[playerid][Cash], pInfo[playerid][Kills], pInfo[playerid][Deaths], pInfo[playerid][ID]);
  122.  
  123.     mysql_tquery(Database, DB_Query);
  124.  
  125.     if(cache_is_valid(pInfo[playerid][Player_Cache])) //Checking if the player's cache ID is valid.
  126.     {
  127.         cache_delete(pInfo[playerid][Player_Cache]); // Deleting the cache.
  128.         pInfo[playerid][Player_Cache] = MYSQL_INVALID_CACHE; // Setting the stored player Cache as invalid.
  129.     }
  130.  
  131.     pInfo[playerid][LoggedIn] = false;
  132.     print("OnPlayerDisconnect has been called."); // Sending message once OnPlayerDisconnect is called.
  133.     return 1;
  134. }
  135.  
  136. public OnPlayerDeath(playerid, killerid, reason)
  137. {
  138.     if(killerid != INVALID_PLAYER_ID) // Checking if the killer of the player is valid.
  139.     {
  140.         //Increasing the kills of the killer and the deaths of the player.
  141.         pInfo[killerid][Kills]++;
  142.         pInfo[playerid][Deaths]++;
  143.     }
  144.     return 1;
  145. }
  146.  
  147. public OnPlayerRequestSpawn(playerid)
  148. {
  149.     if(pInfo[playerid][LoggedIn] == false) return 0; // Ignoring the request incase player isn't logged in.
  150.     return 1;
  151. }
  152.  
  153. public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[])
  154. {
  155.     switch (dialogid)
  156.     {
  157.         case DIALOG_LOGIN:
  158.         {
  159.             if(!response) return Kick(playerid);
  160.  
  161.             new Salted_Key[65];
  162.             SHA256_PassHash(inputtext, pInfo[playerid][Salt], Salted_Key, 65);
  163.  
  164.             if(strcmp(Salted_Key, pInfo[playerid][Password]) == 0)
  165.             {
  166.                 // Now, password should be correct as well as the strings
  167.                 // Matched with each other, so nothing is wrong until now.
  168.                
  169.                 // We will activate the cache of player to make use of it e.g.
  170.                 // Retrieve their data.
  171.                
  172.                 cache_set_active(pInfo[playerid][Player_Cache]);
  173.  
  174.                 // Okay, we are retrieving the information now..
  175.                 cache_get_value_int(0, "ID", pInfo[playerid][ID]);
  176.                
  177.                 cache_get_value_int(0, "KILLS", pInfo[playerid][Kills]);
  178.                 cache_get_value_int(0, "DEATHS", pInfo[playerid][Deaths]);
  179.  
  180.                 cache_get_value_int(0, "SCORE", pInfo[playerid][Score]);
  181.                 cache_get_value_int(0, "CASH", pInfo[playerid][Cash]);
  182.                
  183.                 SetPlayerScore(playerid, pInfo[playerid][Score]);
  184.                
  185.                 ResetPlayerMoney(playerid);
  186.                 GivePlayerMoney(playerid, pInfo[playerid][Cash]);
  187.  
  188.                 // So, we have successfully retrieved data? Now deactivating the cache.
  189.                
  190.                 cache_delete(pInfo[playerid][Player_Cache]);
  191.                 pInfo[playerid][Player_Cache] = MYSQL_INVALID_CACHE;
  192.  
  193.                 pInfo[playerid][LoggedIn] = true;
  194.                 SendClientMessage(playerid, 0x00FF00FF, "Logged in to the account.");
  195.             }
  196.             else
  197.             {
  198.                 new String[150];
  199.                    
  200.                 pInfo[playerid][PasswordFails] += 1;
  201.                 printf("%s has been failed to login. (%d)", pInfo[playerid][Name], pInfo[playerid][PasswordFails]);
  202.                 // Printing the message that someone has failed to login to his account.
  203.  
  204.                 if (pInfo[playerid][PasswordFails] >= 3) // If the fails exceeded the limit we kick the player.
  205.                 {
  206.                     format(String, sizeof(String), "%s has been kicked Reason: {FF0000}(%d/3) Login fails.", pInfo[playerid][Name], pInfo[playerid][PasswordFails]);
  207.                     SendClientMessageToAll(0x969696FF, String);
  208.                     Kick(playerid);
  209.                 }
  210.                 else
  211.                 {
  212.                     // If the player didn't exceed the limits we send him a message that the password is wrong.
  213.                     format(String, sizeof(String), "Wrong password, you have %d out of 3 tries.", pInfo[playerid][PasswordFails]);
  214.                     SendClientMessage(playerid, 0xFF0000FF, String);
  215.                    
  216.                     format(String, sizeof(String), "{FFFFFF}Welcome back, %s.\n\n{0099FF}This account is already registered.\n\
  217.                     {0099FF}Please, input your password below to proceed to the game.\n\n", pInfo[playerid][Name]);
  218.                     ShowPlayerDialog(playerid, DIALOG_LOGIN, DIALOG_STYLE_PASSWORD, "Login System", String, "Login", "Leave");
  219.                 }
  220.             }
  221.         }
  222.         case DIALOG_REGISTER:
  223.         {
  224.             if(!response) return Kick(playerid);
  225.  
  226.             if(strlen(inputtext) <= 5 || strlen(inputtext) > 60)
  227.             {
  228.                 // If the password length is less than or equal to 5 and more than 60
  229.                 // It repeats the process and shows error message as seen below.
  230.                
  231.                 SendClientMessage(playerid, 0x969696FF, "Invalid password length, should be 5 - 60.");
  232.  
  233.                 new String[150];
  234.                
  235.                 format(String, sizeof(String), "{FFFFFF}Welcome %s.\n\n{0099FF}This account is not registered.\n\
  236.                 {0099FF}Please, input your password below to proceed.\n\n", pInfo[playerid][Name]);
  237.                 ShowPlayerDialog(playerid, DIALOG_REGISTER, DIALOG_STYLE_PASSWORD, "Registration System", String, "Register", "Leave");
  238.             }
  239.             else
  240.             {
  241.  
  242.                 // Salting the player's password using SHA256 for a better security.
  243.            
  244.                 for (new i = 0; i < 10; i++)
  245.                 {
  246.                     pInfo[playerid][Salt][i] = random(79) + 47;
  247.                 }
  248.                
  249.                 pInfo[playerid][Salt][10] = 0;
  250.                 SHA256_PassHash(inputtext, pInfo[playerid][Salt], pInfo[playerid][Password], 65);
  251.  
  252.                 new DB_Query[225];
  253.            
  254.                 // Storing player's information if everything goes right.
  255.                 mysql_format(Database, DB_Query, sizeof(DB_Query), "INSERT INTO `PLAYERS` (`USERNAME`, `PASSWORD`, `SALT`, `SCORE`, `KILLS`, `CASH`, `DEATHS`)\
  256.                 VALUES ('%e', '%s', '%e', '20', '0', '0', '0')", pInfo[playerid][Name], pInfo[playerid][Password], pInfo[playerid][Salt]);
  257.                 mysql_tquery(Database, DB_Query, "OnPlayerRegister", "d", playerid);
  258.              }
  259.         }
  260.     }
  261.     return 1;
  262. }
  263.  
  264. forward public OnPlayerDataCheck(playerid, corrupt_check);
  265. public OnPlayerDataCheck(playerid, corrupt_check)
  266. {
  267.     if (corrupt_check != Corrupt_Check[playerid]) return Kick(playerid);
  268.     // You'd have asked already what's corrput_check and how it'd benefit me?
  269.     // Well basically MySQL query takes long, incase a player leaves while its not proceeded
  270.     // With ID 1 for example, then another player comes as ID 1 it'll basically corrupt the data
  271.     // So, once the query is done, the player will have the wrong data assigned for himself.
  272.  
  273.     new String[150];
  274.    
  275.     if(cache_num_rows() > 0)
  276.     {
  277.         // If the player exists, everything is okay and nothing is wrongly detected
  278.         // The player's password and Saltion key gets stored as seen below
  279.         // So we won't have to get a headache just to match player's password.
  280.        
  281.         cache_get_value(0, "PASSWORD", pInfo[playerid][Password], 65);
  282.         cache_get_value(0, "SALT", pInfo[playerid][Salt], 11);
  283.  
  284.         pInfo[playerid][Player_Cache] = cache_save();
  285.         // ^ Storing the cache ID of the player for further use later.
  286.  
  287.         format(String, sizeof(String), "{FFFFFF}Welcome back, %s.\n\n{0099FF}This account is already registered.\n\
  288.         {0099FF}Please, input your password below to proceed to the game.\n\n", pInfo[playerid][Name]);
  289.         ShowPlayerDialog(playerid, DIALOG_LOGIN, DIALOG_STYLE_PASSWORD, "Login System", String, "Login", "Leave");
  290.     }
  291.     else
  292.     {
  293.         format(String, sizeof(String), "{FFFFFF}Welcome %s.\n\n{0099FF}This account is not registered.\n\
  294.         {0099FF}Please, input your password below to proceed to the game.\n\n", pInfo[playerid][Name]);
  295.         ShowPlayerDialog(playerid, DIALOG_REGISTER, DIALOG_STYLE_PASSWORD, "Registration System", String, "Register", "Leave");
  296.     }
  297.     return 1;
  298. }
  299.  
  300. forward public OnPlayerRegister(playerid);
  301. public OnPlayerRegister(playerid)
  302. {
  303.     // This gets called only when the player registers a new account.
  304.     SendClientMessage(playerid, 0x00FF00FF, "You are now registered and has been logged in.");
  305.     pInfo[playerid][LoggedIn] = true;
  306.     return 1;
  307. }
  308.  
  309. // End of script //
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement