Advertisement
Guest User

Untitled

a guest
Jul 17th, 2019
261
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Pawn 13.32 KB | None | 0 0
  1. #include    <a_samp>
  2.  
  3. // change MAX_PLAYERS to the amount of players (slots) you want
  4. // It is by default 1000 (as of 0.3.7 version)
  5. #undef      MAX_PLAYERS
  6. #define     MAX_PLAYERS         100
  7.  
  8. #include    <a_mysql>
  9.  
  10. // MySQL configuration
  11. #define     MYSQL_HOST          "127.0.0.1"
  12. #define     MYSQL_USER          "root"
  13. #define     MYSQL_PASSWORD      "11211121"
  14. #define     MYSQL_DATABASE      "samp"
  15.  
  16. // how many seconds until it kicks the player for taking too long to login
  17. #define     SECONDS_TO_LOGIN    30
  18.  
  19. // default spawn point: Las Venturas (The High Roller)
  20. #define     DEFAULT_POS_X       1958.3783
  21. #define     DEFAULT_POS_Y       1343.1572
  22. #define     DEFAULT_POS_Z       15.3746
  23. #define     DEFAULT_POS_A       270.1425
  24. #define     DEFAULT_SKIN        264
  25.  
  26. // MySQL connection handle
  27. new MySQL: g_SQL;
  28.  
  29. // player data
  30. enum E_PLAYERS
  31. {
  32.     ID,
  33.     Name[MAX_PLAYER_NAME],
  34.     Password[65], // the output of SHA256_PassHash function (which was added in 0.3.7 R1 version) is always 256 bytes in length, or the equivalent of 64 Pawn cells
  35.     Salt[17],
  36.     Kills,
  37.     Deaths,
  38.     Float: Pos_X,
  39.     Float: Pos_Y,
  40.     Float: Pos_Z,
  41.     Float: Pos_A,
  42.     Interior,
  43.     Skin,
  44.     Account,
  45.  
  46.     Cache: Cache_ID,
  47.     bool: IsLoggedIn,
  48.     LoginAttempts,
  49.     LoginTimer
  50. };
  51. new Player[MAX_PLAYERS][E_PLAYERS];
  52.  
  53. new g_MysqlRaceCheck[MAX_PLAYERS];
  54.  
  55. // dialog data
  56. enum
  57. {
  58.     DIALOG_UNUSED,
  59.  
  60.     DIALOG_LOGIN,
  61.     DIALOG_REGISTER
  62. };
  63.  
  64. main() {}
  65.  
  66.  
  67. public OnGameModeInit()
  68. {
  69.     new MySQLOpt: option_id = mysql_init_options();
  70.  
  71.     mysql_set_option(option_id, AUTO_RECONNECT, true); // it automatically reconnects when loosing connection to mysql server
  72.  
  73.     g_SQL = mysql_connect(MYSQL_HOST, MYSQL_USER, MYSQL_PASSWORD, MYSQL_DATABASE, option_id); // AUTO_RECONNECT is enabled for this connection handle only
  74.     if (g_SQL == MYSQL_INVALID_HANDLE || mysql_errno(g_SQL) != 0)
  75.     {
  76.         print("MySQL connection failed. Server is shutting down.");
  77.         SendRconCommand("exit"); // close the server if there is no connection
  78.         return 1;
  79.     }
  80.  
  81.     print("MySQL connection is successful.");
  82.     return 1;
  83. }
  84.  
  85. public OnGameModeExit()
  86. {
  87.     // save all player data before closing connection
  88.     for (new i = 0, j = GetPlayerPoolSize(); i <= j; i++) // GetPlayerPoolSize function was added in 0.3.7 version and gets the highest playerid currently in use on the server
  89.     {
  90.         if (IsPlayerConnected(i))
  91.         {
  92.             // reason is set to 1 for normal 'Quit'
  93.             OnPlayerDisconnect(i, 1);
  94.         }
  95.     }
  96.  
  97.     mysql_close(g_SQL);
  98.     return 1;
  99. }
  100.  
  101. public OnPlayerConnect(playerid)
  102. {
  103.     g_MysqlRaceCheck[playerid]++;
  104.     ResetPlayerData(playerid);
  105.     return 1;
  106. }
  107.  
  108. public OnPlayerRequestClass(playerid, classid)
  109. {
  110.     if (Player[playerid][IsLoggedIn] == false)
  111.     {
  112.         TogglePlayerSpectating(playerid, true);
  113.         SetTimerEx("OnPlayerRequestClassEx", 400, false, "d", playerid); // 400 ms
  114.         return 0;
  115.     }
  116.     else if(Player[playerid][IsLoggedIn] == true)
  117.     {
  118.         SpawnPlayer(playerid);
  119.         return 0;
  120.     }
  121.     else return 0;
  122. }
  123.  
  124. forward OnPlayerRequestClassEx(playerid);
  125. public OnPlayerRequestClassEx(playerid)
  126. {
  127.     OnPlayerConnectEx(playerid);
  128.     SetPlayerCamera(playerid);
  129.     return 1;
  130. }
  131.  
  132. OnPlayerConnectEx(playerid) {
  133.     GetPlayerName(playerid, Player[playerid][Name], MAX_PLAYER_NAME);
  134.  
  135.     // send a query to recieve all the stored player data from the table
  136.     new query[103];
  137.     mysql_format(g_SQL, query, sizeof query, "SELECT * FROM `players` WHERE `Username` = '%e' LIMIT 1", Player[playerid][Name]);
  138.     mysql_tquery(g_SQL, query, "OnPlayerDataLoaded", "dd", playerid, g_MysqlRaceCheck[playerid]);
  139. }
  140.  
  141. SetPlayerCamera(playerid)
  142. {
  143.     SetPlayerCameraPos(playerid, 1249.3018, -1697.8046, 99.9554);
  144.     SetPlayerCameraLookAt(playerid, 1249.6576, -1696.8656, 99.4902);
  145.     return 1;
  146. }
  147.  
  148.  
  149. public OnPlayerDisconnect(playerid, reason)
  150. {
  151.     g_MysqlRaceCheck[playerid]++;
  152.  
  153.     UpdatePlayerData(playerid, reason);
  154.  
  155.     // if the player was kicked (either wrong password or taking too long) during the login part, remove the data from the memory
  156.     if (cache_is_valid(Player[playerid][Cache_ID]))
  157.     {
  158.         cache_delete(Player[playerid][Cache_ID]);
  159.         Player[playerid][Cache_ID] = MYSQL_INVALID_CACHE;
  160.     }
  161.  
  162.     // if the player was kicked before the time expires (30 seconds), kill the timer
  163.     if (Player[playerid][LoginTimer])
  164.     {
  165.         KillTimer(Player[playerid][LoginTimer]);
  166.         Player[playerid][LoginTimer] = 0;
  167.     }
  168.  
  169.     // sets "IsLoggedIn" to false when the player disconnects, it prevents from saving the player data twice when "gmx" is used
  170.     Player[playerid][IsLoggedIn] = false;
  171.     return 1;
  172. }
  173.  
  174. public OnPlayerSpawn(playerid)
  175. {
  176.     // spawn the player to their last saved position
  177.     SetPlayerInterior(playerid, Player[playerid][Interior]);
  178.     SetPlayerPos(playerid, Player[playerid][Pos_X], Player[playerid][Pos_Y], Player[playerid][Pos_Z]);
  179.     SetPlayerFacingAngle(playerid, Player[playerid][Pos_A]);
  180.     SetPlayerSkin(playerid, Player[playerid][Skin]);
  181.  
  182.     SetCameraBehindPlayer(playerid);
  183.     return 1;
  184. }
  185.  
  186. public OnPlayerDeath(playerid, killerid, reason)
  187. {
  188.     return 1;
  189. }
  190.  
  191. public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[])
  192. {
  193.     switch (dialogid)
  194.     {
  195.         case DIALOG_UNUSED: return 1; // Useful for dialogs that contain only information and we do nothing depending on whether they responded or not
  196.  
  197.         case DIALOG_LOGIN:
  198.         {
  199.             if (!response) return Kick(playerid);
  200.  
  201.             new hashed_pass[65];
  202.             SHA256_PassHash(inputtext, Player[playerid][Salt], hashed_pass, 65);
  203.  
  204.             if (strcmp(hashed_pass, Player[playerid][Password]) == 0)
  205.             {
  206.  
  207.                 // sets the specified cache as the active cache so we can retrieve the rest player data
  208.                 cache_set_active(Player[playerid][Cache_ID]);
  209.  
  210.                 AssignPlayerData(playerid);
  211.  
  212.                 // remove the active cache from memory and unsets the active cache as well
  213.                 cache_delete(Player[playerid][Cache_ID]);
  214.                 Player[playerid][Cache_ID] = MYSQL_INVALID_CACHE;
  215.  
  216.                 KillTimer(Player[playerid][LoginTimer]);
  217.                 Player[playerid][LoginTimer] = 0;
  218.                 Player[playerid][IsLoggedIn] = true;
  219.                 TogglePlayerSpectating(playerid, false);
  220.  
  221.                 // spawn the player to their last saved position after login
  222.                 SetSpawnInfo(playerid, NO_TEAM, DEFAULT_SKIN, Player[playerid][Pos_X], Player[playerid][Pos_Y], Player[playerid][Pos_Z], Player[playerid][Pos_A], 0, 0, 0, 0, 0, 0);
  223.                 SpawnPlayer(playerid);
  224.             }
  225.             else
  226.             {
  227.                 Player[playerid][LoginAttempts]++;
  228.  
  229.                 if (Player[playerid][LoginAttempts] >= 3)
  230.                 {
  231.                     ShowPlayerDialog(playerid, DIALOG_UNUSED, DIALOG_STYLE_MSGBOX, "[Login step]", "¤Ø³ãÊèÃËÑʼèÒ¹¼Ô´¶Ö§ 3 ¤ÃÑé§, ¨Ö§â´¹ÃкºàµÐÍÍ¡¨Ò¡à«ÔÃì¿àÇÍÃì", "»Ô´", "");
  232.                     DelayedKick(playerid);
  233.                 }
  234.                 else ShowPlayerDialog(playerid, DIALOG_LOGIN, DIALOG_STYLE_PASSWORD, "[Login step]", "ÃËÑʼèÒ¹äÁè¶Ù¡µéͧ!\n**¡ÃسÒãÊèÃËÑʼèÒ¹à¾×èÍà¢éÒàÅè¹à¡Á!", "à¢éÒà¡Á", "¡àÅÔ¡");
  235.             }
  236.         }
  237.         case DIALOG_REGISTER:
  238.         {
  239.             if (!response) return Kick(playerid);
  240.  
  241.             if (strlen(inputtext) <= 3) return ShowPlayerDialog(playerid, DIALOG_REGISTER, DIALOG_STYLE_PASSWORD, "[Registration step]", "**ÃËÑʼèÒ¹¤ÇÃÁÕÁÒ¡¡ÇèÒ 3 µÑÇÍÑ¡ÉÃ\n***¡ÃسÒãÊèÃËÑʼèÒ¹à¾×èÍŧ·ÐàºÕ¹", "ŧ·ÐàºÕ¹", "¡àÅÔ¡");
  242.  
  243.             // 16 random characters from 33 to 126 (in ASCII) for the salt
  244.             for (new i = 0; i < 16; i++) Player[playerid][Salt][i] = random(94) + 33;
  245.             SHA256_PassHash(inputtext, Player[playerid][Salt], Player[playerid][Password], 65);
  246.  
  247.             new query[221];
  248.             mysql_format(g_SQL, query, sizeof query, "INSERT INTO `players` (`Username`, `Password`, `Salt`) VALUES ('%e', '%s', '%e')", Player[playerid][Name], Player[playerid][Password], Player[playerid][Salt]);
  249.             mysql_tquery(g_SQL, query, "OnPlayerRegister", "d", playerid);
  250.         }
  251.  
  252.         default: return 0; // dialog ID was not found, search in other scripts
  253.     }
  254.     return 1;
  255. }
  256.  
  257. //-----------------------------------------------------
  258.  
  259. forward OnPlayerDataLoaded(playerid, race_check);
  260. public OnPlayerDataLoaded(playerid, race_check)
  261. {
  262.     /*  race condition check:
  263.         player A connects -> SELECT query is fired -> this query takes very long
  264.         while the query is still processing, player A with playerid 2 disconnects
  265.         player B joins now with playerid 2 -> our laggy SELECT query is finally finished, but for the wrong player
  266.  
  267.         what do we do against it?
  268.         we create a connection count for each playerid and increase it everytime the playerid connects or disconnects
  269.         we also pass the current value of the connection count to our OnPlayerDataLoaded callback
  270.         then we check if current connection count is the same as connection count we passed to the callback
  271.         if yes, everything is okay, if not, we just kick the player
  272.     */
  273.     if (race_check != g_MysqlRaceCheck[playerid]) return Kick(playerid);
  274.  
  275.     new string[115];
  276.     if(cache_num_rows() > 0)
  277.     {
  278.         // we store the password and the salt so we can compare the password the player inputs
  279.         // and save the rest so we won't have to execute another query later
  280.         cache_get_value(0, "Password", Player[playerid][Password], 65);
  281.         cache_get_value(0, "Salt", Player[playerid][Salt], 17);
  282.  
  283.         // saves the active cache in the memory and returns an cache-id to access it for later use
  284.         Player[playerid][Cache_ID] = cache_save();
  285.  
  286.         format(string, sizeof string, "ÊÇÑʴդس (%s), ÂÔ¹´Õµé͹ÃѺà¢éÒÊÙèà«ÔÃì¿àÇÍÃì\n**¡ÃسÒãÊèÃËÑʼèÒ¹à¾×èÍà¢éÒàÅè¹à¡Á!", Player[playerid][Name]);
  287.         ShowPlayerDialog(playerid, DIALOG_LOGIN, DIALOG_STYLE_PASSWORD, "[Login step]", string, "à¢éÒà¡Á!", "¡àÅÔ¡");
  288.  
  289.         // from now on, the player has 30 seconds to login
  290.         Player[playerid][LoginTimer] = SetTimerEx("OnLoginTimeout", SECONDS_TO_LOGIN * 1000, false, "d", playerid);
  291.     }
  292.     else
  293.     {
  294.         format(string, sizeof string, "ÊÇÑʴդس (%s), ÂÔ¹´Õµé͹ÃѺà¢éÒÊÙèà«ÔÃì¿àÇÍÃì\n***¡ÃسÒãÊèÃËÑʼèÒ¹à¾×èÍŧ·ÐàºÕ¹", Player[playerid][Name]);
  295.         ShowPlayerDialog(playerid, DIALOG_REGISTER, DIALOG_STYLE_PASSWORD, "[Registration step]", string, "ŧ·ÐàºÕ¹", "¡àÅÔ¡");
  296.     }
  297.     return 1;
  298. }
  299.  
  300. forward OnLoginTimeout(playerid);
  301. public OnLoginTimeout(playerid)
  302. {
  303.     // reset the variable that stores the timerid
  304.     Player[playerid][LoginTimer] = 0;
  305.  
  306.     ShowPlayerDialog(playerid, DIALOG_UNUSED, DIALOG_STYLE_MSGBOX, "[Login step]", "¤Ø³¶Ù¡àµÐÍÍ¡¨Ò¡à«ÔÃì¿àÇÍÃìà¾ÃÒФس AFK", "»Ô´", "");
  307.     DelayedKick(playerid);
  308.     return 1;
  309. }
  310.  
  311. forward OnPlayerRegister(playerid);
  312. public OnPlayerRegister(playerid)
  313. {
  314.     // retrieves the ID generated for an AUTO_INCREMENT column by the sent query
  315.     Player[playerid][ID] = cache_insert_id();
  316.  
  317.     new string[115];
  318.     format(string, sizeof string, "ÊÇÑʴդس (%s), ÂÔ¹´Õµé͹ÃѺà¢éÒÊÙèà«ÔÃì¿àÇÍÃì\n**¡ÃسÒãÊèÃËÑʼèÒ¹à¾×èÍà¢éÒàÅè¹à¡Á!", Player[playerid][Name]);
  319.     ShowPlayerDialog(playerid, DIALOG_LOGIN, DIALOG_STYLE_PASSWORD, "[Login step]", string, "à¢éÒà¡Á!", "¡àÅÔ¡");
  320.     return 1;
  321. }
  322.  
  323. forward _KickPlayerDelayed(playerid);
  324. public _KickPlayerDelayed(playerid)
  325. {
  326.     Kick(playerid);
  327.     return 1;
  328. }
  329.  
  330.  
  331. //-----------------------------------------------------
  332.  
  333. ResetPlayerData(playerid)
  334. {
  335.     Player[playerid][IsLoggedIn] = false;
  336.    
  337.     Player[playerid][Kills] = 0;
  338.     Player[playerid][Deaths] = 0;
  339.  
  340.     Player[playerid][Pos_X] = DEFAULT_POS_X;
  341.     Player[playerid][Pos_Y] = DEFAULT_POS_Y;
  342.     Player[playerid][Pos_Z] = DEFAULT_POS_Z;
  343.     Player[playerid][Pos_A] = DEFAULT_POS_A;
  344.  
  345.     Player[playerid][Interior] = 0;
  346.     Player[playerid][Skin] = DEFAULT_SKIN;
  347.    
  348.     Player[playerid][Account] = 0;
  349.  
  350.     return 1;
  351. }
  352.  
  353. AssignPlayerData(playerid)
  354. {
  355.     cache_get_value_int(0, "ID", Player[playerid][ID]);
  356.  
  357.     cache_get_value_int(0, "Kills", Player[playerid][Kills]);
  358.     cache_get_value_int(0, "Deaths", Player[playerid][Deaths]);
  359.  
  360.     cache_get_value_float(0, "PosX", Player[playerid][Pos_X]);
  361.     cache_get_value_float(0, "PosY", Player[playerid][Pos_Y]);
  362.     cache_get_value_float(0, "PosZ", Player[playerid][Pos_Z]);
  363.     cache_get_value_float(0, "PosA", Player[playerid][Pos_A]);
  364.    
  365.     cache_get_value_int(0, "Interior", Player[playerid][Interior]);
  366.     cache_get_value_int(0, "Skin", Player[playerid][Skin]);
  367.     cache_get_value_int(0, "Account", Player[playerid][Account]);
  368.     return 1;
  369. }
  370.  
  371. DelayedKick(playerid, time = 500)
  372. {
  373.     SetTimerEx("_KickPlayerDelayed", time, false, "d", playerid);
  374.     return 1;
  375. }
  376.  
  377. UpdatePlayerData(playerid, reason)
  378. {
  379.     if (Player[playerid][IsLoggedIn] == false) return 0;
  380.  
  381.     // if the client crashed, it's not possible to get the player's position in OnPlayerDisconnect callback
  382.     // so we will use the last saved position (in case of a player who registered and crashed/kicked, the position will be the default spawn point)
  383.     if (reason == 1)
  384.     {
  385.         GetPlayerPos(playerid, Player[playerid][Pos_X], Player[playerid][Pos_Y], Player[playerid][Pos_Z]);
  386.         GetPlayerFacingAngle(playerid, Player[playerid][Pos_A]);
  387.     }
  388.  
  389.     new query[2048];
  390.     mysql_format(g_SQL, query, sizeof query, "UPDATE `players` SET `PosX` = %f, `PosY` = %f, `PosZ` = %f, `PosA` = %f, `Interior` = %d, `Kills` = %d, `Deaths` = %d, \
  391.     `Skin` = %d, `Account` = %d WHERE `ID` = %d LIMIT 1",
  392.     Player[playerid][Pos_X], Player[playerid][Pos_Y], Player[playerid][Pos_Z], Player[playerid][Pos_A], GetPlayerInterior(playerid), Player[playerid][Kills],
  393.     Player[playerid][Deaths], Player[playerid][Skin], Player[playerid][Account], Player[playerid][ID]);
  394.     mysql_tquery(g_SQL, query);
  395.     return 1;
  396. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement