Guest User

GM

a guest
Aug 5th, 2018
122
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Pawn 15.16 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         50
  7.  
  8. #include    <a_mysql>
  9. #include    <zcmd>
  10. #include    <sscanf2>
  11.  
  12. // MySQL configuration
  13. #define     MYSQL_HOST          "127.0.0.1"
  14. #define     MYSQL_USER          "root"
  15. #define     MYSQL_PASSWORD      "11211121"
  16. #define     MYSQL_DATABASE      "samp"
  17.  
  18. // Reverse function
  19. #define function:%0(%1) forward %0(%1); public %0(%1)
  20.  
  21. // how many seconds until it kicks the player for taking too long to login
  22. #define     SECONDS_TO_LOGIN    30
  23.  
  24. // Spawn players points
  25. #define     SPAWN_POINT_AIRPORT     (0)
  26.  
  27. // MySQL connection handle
  28. new MySQL: g_SQL;
  29.  
  30. // WP_hash
  31. native WP_Hash(buffer[], len, const str[]);
  32.  
  33. // player data
  34. enum E_PLAYERS
  35. {
  36.     pID,
  37.     pName[MAX_PLAYER_NAME],
  38.     pPassword[129],
  39.     pKills,
  40.     pDeaths,
  41.     Float: pPosX,
  42.     Float: pPosY,
  43.     Float: pPosZ,
  44.     Float: pPosA,
  45.     pInterior,
  46.     pInjured,
  47.     pSpawnPoint,
  48.     pSkin,
  49.  
  50.     Cache: Cache_ID,
  51.     bool: IsLoggedIn,
  52.     LoginAttempts,
  53.     LoginTimer
  54. };
  55. new PlayerInfo[MAX_PLAYERS][E_PLAYERS];
  56.  
  57. new g_MysqlRaceCheck[MAX_PLAYERS];
  58.  
  59. // dialog data
  60. enum
  61. {
  62.     DIALOG_UNUSED,
  63.  
  64.     DIALOG_LOGIN,
  65.     DIALOG_REGISTER
  66. };
  67.  
  68. main() {}
  69.  
  70.  
  71. public OnGameModeInit()
  72. {
  73.     new MySQLOpt: option_id = mysql_init_options();
  74.  
  75.     mysql_set_option(option_id, AUTO_RECONNECT, true); // it automatically reconnects when loosing connection to mysql server
  76.  
  77.     g_SQL = mysql_connect(MYSQL_HOST, MYSQL_USER, MYSQL_PASSWORD, MYSQL_DATABASE, option_id); // AUTO_RECONNECT is enabled for this connection handle only
  78.     if (g_SQL == MYSQL_INVALID_HANDLE || mysql_errno(g_SQL) != 0)
  79.     {
  80.         print("MySQL connection failed. Server is shutting down.");
  81.         SendRconCommand("exit"); // close the server if there is no connection
  82.         return 1;
  83.     }
  84.     mysql_log(ALL);
  85.     print("MySQL connection is successful.");
  86.     return 1;
  87. }
  88.  
  89. public OnGameModeExit()
  90. {
  91.     // save all player data before closing connection
  92.     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
  93.     {
  94.         if (IsPlayerConnected(i))
  95.         {
  96.             // reason is set to 1 for normal 'Quit'
  97.             OnPlayerDisconnect(i, 1);
  98.         }
  99.     }
  100.  
  101.     mysql_close(g_SQL);
  102.     return 1;
  103. }
  104.  
  105. function:Camera(playerid)
  106. {
  107.     SetPlayerCameraPos(playerid, 1849.9003, -1428.3875, 295.0201);
  108.     SetPlayerCameraLookAt(playerid, 1849.0439, -1427.8647, 294.7950);
  109.     print("Camera running");
  110.     return 1;
  111. }
  112.  
  113. public OnPlayerConnect(playerid)
  114. {
  115.     g_MysqlRaceCheck[playerid]++;
  116.  
  117.     // reset player data
  118.     ResetPlayer(playerid);
  119. /*  static const empty_player[E_PLAYERS];
  120.     PlayerInfo[playerid] = empty_player;*/
  121.  
  122.     GetPlayerName(playerid, PlayerInfo[playerid][pName], MAX_PLAYER_NAME);
  123.     Camera(playerid);
  124.     // send a query to recieve all the stored player data from the table
  125.     new query[103];
  126.     mysql_format(g_SQL, query, sizeof query, "SELECT * FROM `players` WHERE `Username` = '%e' LIMIT 1", PlayerInfo[playerid][pName]);
  127.     mysql_tquery(g_SQL, query, "OnPlayerDataLoaded", "dd", playerid, g_MysqlRaceCheck[playerid]);
  128.     print("OnPlayerConnect running");
  129.     return 1;
  130. }
  131.  
  132. public OnPlayerDisconnect(playerid, reason)
  133. {
  134.     g_MysqlRaceCheck[playerid]++;
  135.  
  136.     UpdatePlayerData(playerid, reason);
  137.  
  138.     // if the player was kicked (either wrong password or taking too long) during the login part, remove the data from the memory
  139.     if (cache_is_valid(PlayerInfo[playerid][Cache_ID]))
  140.     {
  141.         cache_delete(PlayerInfo[playerid][Cache_ID]);
  142.         PlayerInfo[playerid][Cache_ID] = MYSQL_INVALID_CACHE;
  143.     }
  144.  
  145.     // if the player was kicked before the time expires (30 seconds), kill the timer
  146.     if (PlayerInfo[playerid][LoginTimer])
  147.     {
  148.         KillTimer(PlayerInfo[playerid][LoginTimer]);
  149.         PlayerInfo[playerid][LoginTimer] = 0;
  150.     }
  151.  
  152.     // sets "IsLoggedIn" to false when the player disconnects, it prevents from saving the player data twice when "gmx" is used
  153.     PlayerInfo[playerid][IsLoggedIn] = false;
  154.     return 1;
  155. }
  156.  
  157. public OnPlayerRequestClass(playerid, classid)
  158. {
  159.     if (PlayerInfo[playerid][IsLoggedIn] == false)
  160.     {
  161.         Camera(playerid);
  162.         TogglePlayerSpectating(playerid, true);
  163.         print("OnPlayerRequestClass running");
  164.         return 0;
  165.     }
  166.     else if(PlayerInfo[playerid][IsLoggedIn] == true)
  167.     {
  168.         SetSpawnInfo(playerid, 0, PlayerInfo[playerid][pSkin], PlayerInfo[playerid][pPosX], PlayerInfo[playerid][pPosY], PlayerInfo[playerid][pPosZ], PlayerInfo[playerid][pPosA], 0, 0, 0, 0, 0, 0);
  169.         SpawnPlayer(playerid);
  170.         print("OnPlayerRequestClass Login running");
  171.         return 0;
  172.     }
  173.     else return 0;
  174. }
  175.  
  176. public OnPlayerSpawn(playerid)
  177. {
  178.     SetPlayersSpawn(playerid);
  179.     SetCameraBehindPlayer(playerid);
  180.     print("OnPlayerSpawn running");
  181.     return 1;
  182. }
  183.  
  184. function:SetPlayersSpawn(playerid)
  185. {
  186.     switch(PlayerInfo[playerid][pSpawnPoint])
  187.     {
  188.         case SPAWN_POINT_AIRPORT:
  189.         {
  190.             if(PlayerInfo[playerid][pInjured] > 0)
  191.             {
  192.                 SetPlayerPos(playerid, 1642.02, -2334.05, 13.5469);
  193.                 SetPlayerFacingAngle(playerid, 0.5602);
  194.  
  195.                 SetPlayerInterior(playerid, 0);
  196.                 SetPlayerVirtualWorld(playerid, 0);
  197.                 SetPlayerSkin(playerid, PlayerInfo[playerid][pSkin]);
  198.                 PlayerInfo[playerid][pInjured] = 0;
  199.             }
  200.             else
  201.             {
  202.                 SetPlayerInterior(playerid, PlayerInfo[playerid][pInterior]);
  203.                 SetPlayerPos(playerid, PlayerInfo[playerid][pPosX], PlayerInfo[playerid][pPosY], PlayerInfo[playerid][pPosZ]);
  204.                 SetPlayerFacingAngle(playerid, PlayerInfo[playerid][pPosA]);
  205.             }
  206.         }
  207.     }
  208.     return 1;
  209. }
  210.  
  211. public OnPlayerDeath(playerid, killerid, reason)
  212. {
  213.     PlayerInfo[playerid][pInjured] ++;
  214.     return 1;
  215. }
  216.  
  217. public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[])
  218. {
  219.     switch (dialogid)
  220.     {
  221.         case DIALOG_UNUSED: return 1; // Useful for dialogs that contain only information and we do nothing depending on whether they responded or not
  222.  
  223.         case DIALOG_LOGIN:
  224.         {
  225.             if (!response) return Kick(playerid);
  226.  
  227.             new hashed_pass[129];
  228.  
  229.             WP_Hash(hashed_pass, sizeof(hashed_pass), inputtext);
  230.  
  231.             if (strcmp(hashed_pass, PlayerInfo[playerid][pPassword]) == 0)
  232.             {
  233.                 //correct password, spawn the player
  234.                 ShowPlayerDialog(playerid, DIALOG_UNUSED, DIALOG_STYLE_MSGBOX, "Login", "You have been successfully logged in.", "Okay", "");
  235.  
  236.                 // sets the specified cache as the active cache so we can retrieve the rest player data
  237.                 cache_set_active(PlayerInfo[playerid][Cache_ID]);
  238.  
  239.                 AssignPlayerData(playerid);
  240.  
  241.                 // remove the active cache from memory and unsets the active cache as well
  242.                 cache_delete(PlayerInfo[playerid][Cache_ID]);
  243.                 PlayerInfo[playerid][Cache_ID] = MYSQL_INVALID_CACHE;
  244.  
  245.                 KillTimer(PlayerInfo[playerid][LoginTimer]);
  246.                 PlayerInfo[playerid][LoginTimer] = 0;
  247.                 new query[128];
  248.                 mysql_format(g_SQL, query, sizeof(query), "SELECT * FROM players WHERE Username = '%e' LIMIT 1", PlayerInfo[playerid][pName]);
  249.                 mysql_tquery(g_SQL, query, "OnPlayerLogin", "d", playerid);
  250.                 print("DIALOG_LOGIN pass correct running");
  251.             }
  252.             else
  253.             {
  254.                 PlayerInfo[playerid][LoginAttempts]++;
  255.  
  256.                 if (PlayerInfo[playerid][LoginAttempts] >= 3)
  257.                 {
  258.                     ShowPlayerDialog(playerid, DIALOG_UNUSED, DIALOG_STYLE_MSGBOX, "Login", "You have mistyped your password too often (3 times).", "Okay", "");
  259.                     DelayedKick(playerid);
  260.                     print("DIALOG_LOGIN pass incorrect running");
  261.                 }
  262.                 else
  263.                 {
  264.                     ShowPlayerDialog(playerid, DIALOG_LOGIN, DIALOG_STYLE_PASSWORD, "Login", "Wrong password!\nPlease enter your password in the field below:", "Login", "Abort");
  265.                     print("DIALOG_LOGIN pass incorrect running2");
  266.                 }
  267.             }
  268.             Camera(playerid);
  269.         }
  270.         case DIALOG_REGISTER:
  271.         {
  272.             if (!response) return Kick(playerid);
  273.  
  274.             if (strlen(inputtext) <= 5) return ShowPlayerDialog(playerid, DIALOG_REGISTER, DIALOG_STYLE_PASSWORD, "Registration", "Your password must be longer than 5 characters!\nPlease enter your password in the field below:", "Register", "Abort");
  275.  
  276.             new query[256];
  277.             WP_Hash(PlayerInfo[playerid][pPassword], 129, inputtext);
  278.  
  279.             mysql_format(g_SQL, query, sizeof query, "INSERT INTO `players` (`Username`, `Password`) VALUES ('%e', '%s')", PlayerInfo[playerid][pName], PlayerInfo[playerid][pPassword]);
  280.             mysql_tquery(g_SQL, query, "OnPlayerRegister", "d", playerid);
  281.             print("DIALOG_REGISTER running");
  282.         }
  283.  
  284.         default: return 0; // dialog ID was not found, search in other scripts
  285.     }
  286.     return 1;
  287. }
  288.  
  289. //-----------------------------------------------------
  290.  
  291. function:OnPlayerLogin(playerid)
  292. {
  293.     PlayerInfo[playerid][IsLoggedIn] = true;
  294.     TogglePlayerSpectating(playerid, false);
  295.     // spawn the player to their last saved position after login
  296.     SetSpawnInfo(playerid, 0, PlayerInfo[playerid][pSkin], PlayerInfo[playerid][pPosX], PlayerInfo[playerid][pPosY], PlayerInfo[playerid][pPosZ], PlayerInfo[playerid][pPosA], 0, 0, 0, 0, 0, 0);
  297.     SpawnPlayer(playerid);
  298.     print("OnPlayerLogin running");
  299.     return 1;
  300. }
  301.  
  302. function:OnPlayerRegister(playerid)
  303. {
  304.     // retrieves the ID generated for an AUTO_INCREMENT column by the sent query
  305.     PlayerInfo[playerid][pID] = cache_insert_id();
  306.  
  307.     ShowPlayerDialog(playerid, DIALOG_UNUSED, DIALOG_STYLE_MSGBOX, "Registration", "Account successfully registered, you have been automatically logged in.", "Okay", "");
  308.  
  309.     PlayerInfo[playerid][IsLoggedIn] = true;
  310.     TogglePlayerSpectating(playerid, false);
  311.  
  312.     SetSpawnInfo(playerid, 0, PlayerInfo[playerid][pSkin], PlayerInfo[playerid][pPosX], PlayerInfo[playerid][pPosY], PlayerInfo[playerid][pPosZ], PlayerInfo[playerid][pPosA], 0, 0, 0, 0, 0, 0);
  313.     SpawnPlayer(playerid);
  314.     print("OnPlayerRegister running");
  315.     return 1;
  316. }
  317.  
  318. function:ResetPlayer(playerid)
  319. {
  320.     //Player characters:
  321.     PlayerInfo[playerid][IsLoggedIn] = false;
  322.     PlayerInfo[playerid][pID] = 0;
  323.     PlayerInfo[playerid][pKills] = 0;
  324.     PlayerInfo[playerid][pDeaths] = 0;
  325.  
  326.     PlayerInfo[playerid][pPosX] = 1642.02;
  327.     PlayerInfo[playerid][pPosY] = -2334.05;
  328.     PlayerInfo[playerid][pPosZ] = 13.5469;
  329.     PlayerInfo[playerid][pPosA] = 0.5602;
  330.  
  331.     PlayerInfo[playerid][pInterior] = 0;
  332.     PlayerInfo[playerid][pInjured] = 0;
  333.     PlayerInfo[playerid][pSpawnPoint] = 0;
  334.     PlayerInfo[playerid][pSkin] = 264;
  335.     return 1;
  336. }
  337.  
  338. function:OnPlayerDataLoaded(playerid, race_check)
  339. {
  340.     /*  race condition check:
  341.         player A connects -> SELECT query is fired -> this query takes very long
  342.         while the query is still processing, player A with playerid 2 disconnects
  343.         player B joins now with playerid 2 -> our laggy SELECT query is finally finished, but for the wrong player
  344.  
  345.         what do we do against it?
  346.         we create a connection count for each playerid and increase it everytime the playerid connects or disconnects
  347.         we also pass the current value of the connection count to our OnPlayerDataLoaded callback
  348.         then we check if current connection count is the same as connection count we passed to the callback
  349.         if yes, everything is okay, if not, we just kick the player
  350.     */
  351.     if (race_check != g_MysqlRaceCheck[playerid]) return Kick(playerid);
  352.  
  353.     new string[115];
  354.     if(cache_num_rows() > 0)
  355.     {
  356.         cache_get_value(0, "Password", PlayerInfo[playerid][pPassword], 129);
  357.  
  358.         // saves the active cache in the memory and returns an cache-id to access it for later use
  359.         PlayerInfo[playerid][Cache_ID] = cache_save();
  360.  
  361.         format(string, sizeof string, "This account (%s) is registered. Please login by entering your password in the field below:", PlayerInfo[playerid][pName]);
  362.         ShowPlayerDialog(playerid, DIALOG_LOGIN, DIALOG_STYLE_PASSWORD, "Login", string, "Login", "Abort");
  363.  
  364.         // from now on, the player has 30 seconds to login
  365.         PlayerInfo[playerid][LoginTimer] = SetTimerEx("OnLoginTimeout", SECONDS_TO_LOGIN * 1000, false, "d", playerid);
  366.     }
  367.     else
  368.     {
  369.         format(string, sizeof string, "Welcome %s, you can register by entering your password in the field below:", PlayerInfo[playerid][pName]);
  370.         ShowPlayerDialog(playerid, DIALOG_REGISTER, DIALOG_STYLE_PASSWORD, "Registration", string, "Register", "Abort");
  371.     }
  372.     Camera(playerid);
  373.     print("OnPlayerDataLoaded running");
  374.     return 1;
  375. }
  376.  
  377. function:OnLoginTimeout(playerid)
  378. {
  379.     // reset the variable that stores the timerid
  380.     PlayerInfo[playerid][LoginTimer] = 0;
  381.  
  382.     ShowPlayerDialog(playerid, DIALOG_UNUSED, DIALOG_STYLE_MSGBOX, "Login", "You have been kicked for taking too long to login successfully to your account.", "Okay", "");
  383.     DelayedKick(playerid);
  384.     return 1;
  385. }
  386.  
  387. function:KickPlayerDelayed(playerid)
  388. {
  389.     Kick(playerid);
  390.     return 1;
  391. }
  392.  
  393. //-----------------------------------------------------
  394.  
  395. AssignPlayerData(playerid)
  396. {
  397.     cache_get_value_int(0, "ID", PlayerInfo[playerid][pID]);
  398.  
  399.     cache_get_value_int(0, "Kills", PlayerInfo[playerid][pKills]);
  400.     cache_get_value_int(0, "Deaths", PlayerInfo[playerid][pDeaths]);
  401.  
  402.     cache_get_value_float(0, "PosX", PlayerInfo[playerid][pPosX]);
  403.     cache_get_value_float(0, "PosY", PlayerInfo[playerid][pPosY]);
  404.     cache_get_value_float(0, "PosZ", PlayerInfo[playerid][pPosZ]);
  405.     cache_get_value_float(0, "PosA", PlayerInfo[playerid][pPosA]);
  406.     cache_get_value_int(0, "Interior", PlayerInfo[playerid][pInterior]);
  407.     cache_get_value_int(0, "Injured", PlayerInfo[playerid][pInjured]);
  408.     cache_get_value_int(0, "SpawnPoint", PlayerInfo[playerid][pSpawnPoint]);
  409.     cache_get_value_int(0, "Skin", PlayerInfo[playerid][pSkin]);
  410.     return 1;
  411. }
  412.  
  413. DelayedKick(playerid, time = 500)
  414. {
  415.     SetTimerEx("KickPlayerDelayed", time, false, "d", playerid);
  416.     return 1;
  417. }
  418.  
  419. UpdatePlayerData(playerid, reason)
  420. {
  421.     if (PlayerInfo[playerid][IsLoggedIn] == false) return 0;
  422.  
  423.     // if the client crashed, it's not possible to get the player's position in OnPlayerDisconnect callback
  424.     // 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)
  425.     if (reason == 1)
  426.     {
  427.         GetPlayerPos(playerid, PlayerInfo[playerid][pPosX], PlayerInfo[playerid][pPosY], PlayerInfo[playerid][pPosZ]);
  428.         GetPlayerFacingAngle(playerid, PlayerInfo[playerid][pPosA]);
  429.     }
  430.  
  431.     new query[256];
  432.  
  433.     mysql_format(g_SQL, query, sizeof query, "UPDATE `players` SET `PosX` = %f, `PosY` = %f, `PosZ` = %f, `PosA` = %f, `Interior` = %d WHERE `ID` = %d",
  434.         PlayerInfo[playerid][pPosX],
  435.         PlayerInfo[playerid][pPosY],
  436.         PlayerInfo[playerid][pPosZ],
  437.         PlayerInfo[playerid][pPosA],
  438.         GetPlayerInterior(playerid),
  439.         PlayerInfo[playerid][pID]);
  440.     mysql_tquery(g_SQL, query);
  441.  
  442.     mysql_format(g_SQL, query, sizeof query, "UPDATE `players` SET `Deaths` = %d, `Kills` = %d, `Injured` = %d, `SpawnPoint` = %d, `Skin` = %d WHERE `ID` = %d",
  443.         PlayerInfo[playerid][pDeaths],
  444.         PlayerInfo[playerid][pKills],
  445.         PlayerInfo[playerid][pInjured],
  446.         PlayerInfo[playerid][pKills],
  447.         PlayerInfo[playerid][pSkin],
  448.         PlayerInfo[playerid][pID]);
  449.     mysql_tquery(g_SQL, query);
  450.     return 1;
  451. }
  452.  
  453. /* Test commands*/
  454. CMD:test(playerid, params[])
  455. {
  456.     SetPlayerHealth(playerid, 0);
  457.     return 1;
  458. }
  459.  
  460. CMD:skin(playerid, params[])
  461. {
  462.     new playerb, skinid;
  463.  
  464.     if (sscanf(params, "ud", playerb, skinid))
  465.         return SendClientMessage(playerid, -1, "/skin [playerid OR name] [skinid]");
  466.  
  467.     if(!IsPlayerConnected(playerb))
  468.         return SendClientMessage(playerid, -1, "The player you specified isn't connected.");
  469.  
  470.     if(PlayerInfo[playerid][IsLoggedIn] == false)
  471.         return SendClientMessage(playerid, -1, "The player you specified isn't logged in.");
  472.  
  473.     PlayerInfo[playerb][pSkin] = skinid; SetPlayerSkin(playerb, skinid);
  474.     return 1;
  475. }
Add Comment
Please, Sign In to add comment