Advertisement
Guest User

Untitled

a guest
Jan 21st, 2019
98
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 17.07 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.  
  11.  
  12. // MySQL configuration
  13. #define MYSQL_HOST "127.0.0.1"
  14. #define MYSQL_USER "root"
  15. #define MYSQL_PASSWORD "Pass123!"
  16. #define MYSQL_DATABASE "dbrp"
  17.  
  18.  
  19.  
  20. // colori
  21. // system color
  22. #define COLOR_SYSTEM_ERROR 0xAA3333AA
  23. #define COLOR_SYSTEM_TITLE 0xFFFFFFAA
  24. #define COLOR_SYSTEM_TEXT 0xFFFFFFAA
  25. #define COLOR_SYSTEM_SUCCESS 0x33AA33AA
  26. #define COLOR_SYSTEM_INFO 0xAFAFAFAA
  27.  
  28.  
  29. // how many seconds until it kicks the player for taking too long to login
  30. #define SECONDS_TO_LOGIN 30
  31.  
  32. // default spawn point: Las Venturas (The High Roller)
  33. #define DEFAULT_POS_X 1958.3783
  34. #define DEFAULT_POS_Y 1343.1572
  35. #define DEFAULT_POS_Z 15.3746
  36. #define DEFAULT_POS_A 270.1425
  37.  
  38. // MySQL connection handle
  39. new MySQL: g_SQL;
  40.  
  41. // player data
  42. enum E_PLAYERS
  43. {
  44. ID,
  45. Name[MAX_PLAYER_NAME],
  46. 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
  47. Salt[17],
  48. Kills,
  49. Admin,
  50. Age,
  51. Sex,
  52. Deaths,
  53. Float: X_Pos,
  54. Float: Y_Pos,
  55. Float: Z_Pos,
  56. Float: A_Pos,
  57. Interior,
  58.  
  59. Cache: Cache_ID,
  60. bool: IsLoggedIn,
  61. LoginAttempts,
  62. LoginTimer
  63. };
  64. new Player[MAX_PLAYERS][E_PLAYERS];
  65.  
  66. new g_MysqlRaceCheck[MAX_PLAYERS];
  67.  
  68. // dialog data
  69. enum
  70. {
  71. DIALOG_UNUSED,
  72.  
  73. DIALOG_LOGIN,
  74. DIALOG_REGISTER,
  75. DIALOG_REGISTER_AGE,
  76. DIALOG_REGISTER_SEX
  77. };
  78.  
  79. main() {}
  80.  
  81.  
  82. public OnGameModeInit()
  83. {
  84. new MySQLOpt: option_id = mysql_init_options();
  85.  
  86. mysql_set_option(option_id, AUTO_RECONNECT, true); // it automatically reconnects when loosing connection to mysql server
  87.  
  88. g_SQL = mysql_connect(MYSQL_HOST, MYSQL_USER, MYSQL_PASSWORD, MYSQL_DATABASE, option_id); // AUTO_RECONNECT is enabled for this connection handle only
  89. if (g_SQL == MYSQL_INVALID_HANDLE || mysql_errno(g_SQL) != 0)
  90. {
  91. print("MySQL connection failed. Server is shutting down.");
  92. SendRconCommand("exit"); // close the server if there is no connection
  93. return 1;
  94. }
  95.  
  96. print("MySQL connection is successful.");
  97.  
  98. // if the table has been created, the "SetupPlayerTable" function does not have any purpose so you may remove it completely
  99. SetupPlayerTable();
  100. return 1;
  101. }
  102.  
  103. public OnGameModeExit()
  104. {
  105. // save all player data before closing connection
  106. 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
  107. {
  108. if (IsPlayerConnected(i))
  109. {
  110. // reason is set to 1 for normal 'Quit'
  111. OnPlayerDisconnect(i, 1);
  112. }
  113. }
  114.  
  115. mysql_close(g_SQL);
  116. return 1;
  117. }
  118.  
  119. public OnPlayerConnect(playerid)
  120. {
  121. g_MysqlRaceCheck[playerid]++;
  122.  
  123. // reset player data
  124. static const empty_player[E_PLAYERS];
  125. Player[playerid] = empty_player;
  126.  
  127. GetPlayerName(playerid, Player[playerid][Name], MAX_PLAYER_NAME);
  128.  
  129. // send a query to recieve all the stored player data from the table
  130. new query[103];
  131. mysql_format(g_SQL, query, sizeof query, "SELECT * FROM `players` WHERE `username` = '%e' LIMIT 1", Player[playerid][Name]);
  132. mysql_tquery(g_SQL, query, "OnPlayerDataLoaded", "dd", playerid, g_MysqlRaceCheck[playerid]);
  133. return 1;
  134. }
  135.  
  136. public OnPlayerDisconnect(playerid, reason)
  137. {
  138. g_MysqlRaceCheck[playerid]++;
  139.  
  140. UpdatePlayerData(playerid, reason);
  141.  
  142. // if the player was kicked (either wrong password or taking too long) during the login part, remove the data from the memory
  143. if (cache_is_valid(Player[playerid][Cache_ID]))
  144. {
  145. cache_delete(Player[playerid][Cache_ID]);
  146. Player[playerid][Cache_ID] = MYSQL_INVALID_CACHE;
  147. }
  148.  
  149. // if the player was kicked before the time expires (30 seconds), kill the timer
  150. if (Player[playerid][LoginTimer])
  151. {
  152. KillTimer(Player[playerid][LoginTimer]);
  153. Player[playerid][LoginTimer] = 0;
  154. }
  155.  
  156. // sets "IsLoggedIn" to false when the player disconnects, it prevents from saving the player data twice when "gmx" is used
  157. Player[playerid][IsLoggedIn] = false;
  158. return 1;
  159. }
  160.  
  161. public OnPlayerSpawn(playerid)
  162. {
  163. // spawn the player to their last saved position
  164. SetPlayerInterior(playerid, Player[playerid][Interior]);
  165. SetPlayerPos(playerid, Player[playerid][X_Pos], Player[playerid][Y_Pos], Player[playerid][Z_Pos]);
  166. SetPlayerFacingAngle(playerid, Player[playerid][A_Pos]);
  167.  
  168. SetCameraBehindPlayer(playerid);
  169. return 1;
  170. }
  171.  
  172. public OnPlayerDeath(playerid, killerid, reason)
  173. {
  174. UpdatePlayerDeaths(playerid);
  175. UpdatePlayerKills(killerid);
  176. return 1;
  177. }
  178.  
  179. public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[])
  180. {
  181. switch (dialogid)
  182. {
  183. case DIALOG_UNUSED: return 1; // Useful for dialogs that contain only information and we do nothing depending on whether they responded or not
  184.  
  185. case DIALOG_LOGIN:
  186. {
  187. if (!response) return Kick(playerid);
  188.  
  189. new hashed_pass[65];
  190. SHA256_PassHash(inputtext, Player[playerid][Salt], hashed_pass, 65);
  191.  
  192. if (strcmp(hashed_pass, Player[playerid][Password]) == 0)
  193. {
  194. //correct password, spawn the player
  195. ShowPlayerDialog(playerid, DIALOG_UNUSED, DIALOG_STYLE_MSGBOX, "Login", "Login con successo.", "Okay", "");
  196. // sets the specified cache as the active cache so we can retrieve the rest player data
  197. cache_set_active(Player[playerid][Cache_ID]);
  198. AssignPlayerData(playerid);
  199. // remove the active cache from memory and unsets the active cache as well
  200. cache_delete(Player[playerid][Cache_ID]);
  201. Player[playerid][Cache_ID] = MYSQL_INVALID_CACHE;
  202.  
  203. KillTimer(Player[playerid][LoginTimer]);
  204. Player[playerid][LoginTimer] = 0;
  205. Player[playerid][IsLoggedIn] = true;
  206.  
  207. // spawn the player to their last saved position after login
  208. SetSpawnInfo(playerid, NO_TEAM, 0, Player[playerid][X_Pos], Player[playerid][Y_Pos], Player[playerid][Z_Pos], Player[playerid][A_Pos], 0, 0, 0, 0, 0, 0);
  209. SpawnPlayer(playerid);
  210. }
  211. else
  212. {
  213. Player[playerid][LoginAttempts]++;
  214.  
  215. if (Player[playerid][LoginAttempts] >= 3)
  216. {
  217. ShowPlayerDialog(playerid, DIALOG_UNUSED, DIALOG_STYLE_MSGBOX, "Login", "Hai superato i tentativi di accesso (3 tentativi).", "Okay", "");
  218. DelayedKick(playerid);
  219. }
  220. else ShowPlayerDialog(playerid, DIALOG_LOGIN, DIALOG_STYLE_PASSWORD, "Login", "{FF0000}Password errata!\n{AFAFAF}Inserisci la password per entrare:", "Login", "Annulla");
  221. }
  222. }
  223. case DIALOG_REGISTER:
  224. {
  225. if (!response) return Kick(playerid);
  226.  
  227. if (strlen(inputtext) <= 5) return ShowPlayerDialog(playerid, DIALOG_REGISTER, DIALOG_STYLE_PASSWORD, "Registrazione", "{FF0000}[ERRORE:]Hai inserito una password troppo corta, usa almeno 5 caratteri!\n{AFAFAF}Inserisci una password per registrarti:", "Continua", "Annulla");
  228.  
  229. // 16 random characters from 33 to 126 (in ASCII) for the salt
  230. for (new i = 0; i < 16; i++) Player[playerid][Salt][i] = random(94) + 33;
  231. SHA256_PassHash(inputtext, Player[playerid][Salt], Player[playerid][Password], 65);
  232. new query[221];
  233. 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]);
  234. // mysql_tquery(g_SQL, query, "OnPlayerRegister", "d", playerid);
  235. ShowPlayerDialog(playerid, DIALOG_REGISTER_AGE, DIALOG_STYLE_INPUT, "Registrazione", "Inserisci l'età che vuoi avere nel server\nNon influenzerà il gioco", "Continua", "Annulla");
  236. }
  237.  
  238. case DIALOG_REGISTER_AGE:
  239. {
  240. if (!response) return Kick(playerid);
  241.  
  242. if (!strlen(inputtext)) return ShowPlayerDialog(playerid, DIALOG_REGISTER_AGE, DIALOG_STYLE_INPUT, "Registrazione", "{FF0000}[ERRORE:]Devi inserire l'età per continuare!\n{AFAFAF}Non influenzerà il gioco:", "Continua", "Annulla");
  243. if (!IsNumeric(inputtext)) return ShowPlayerDialog(playerid, DIALOG_REGISTER_AGE, DIALOG_STYLE_INPUT, "Registrazione", "{FF0000}[ERRORE:]Devi inserire un numero per l'età!\n{AFAFAF}Non influenzerà il gioco:", "Continua", "Annulla");
  244. Player[playerid][Age] = strlen(inputtext);
  245. new query[221];
  246. mysql_format(g_SQL, query, sizeof query, "INSERT INTO `players` (`username`, `password`, `salt`, `age`) VALUES ('%e', '%s', '%e', '%d')", Player[playerid][Name], Player[playerid][Password], Player[playerid][Salt], Player[playerid][Age]);
  247. ShowPlayerDialog(playerid, DIALOG_REGISTER_SEX, DIALOG_STYLE_LIST, "Seleziona il sesso", "{FF6666}Donna\n{0000cc}Uomo", "Continua", "");
  248. }
  249.  
  250. case DIALOG_REGISTER_SEX:
  251. {
  252. switch(listitem)// Dialog: registrazione fase 3: sesso
  253. {
  254. case 0: // Registrazione sesso: selezionato: donna
  255. {
  256. Player[playerid][Sex] = 1; // 1 = donna
  257. new query[221];
  258. mysql_format(g_SQL, query, sizeof query, "INSERT INTO `players` (`username`, `password`, `salt`, `age`, `sex`) VALUES ('%e', '%s', '%e', '%d', '%d')", Player[playerid][Name], Player[playerid][Password], Player[playerid][Salt], Player[playerid][Age], Player[playerid][Sex]);
  259. mysql_tquery(g_SQL, query, "OnPlayerRegister", "d", playerid);
  260. new Messaggio[256];
  261. format(Messaggio, sizeof (Messaggio), "[INFO]: %s sei {FF6666}una donna", Player[playerid][Name]);
  262. SendClientMessage(playerid, COLOR_SYSTEM_INFO, Messaggio);
  263. }
  264. case 1: // Registrazione sesso: selezionato: uomo
  265. {
  266. Player[playerid][Sex] = 2; // 2 = uomo
  267. new query[221];
  268. mysql_format(g_SQL, query, sizeof query, "INSERT INTO `players` (`username`, `password`, `salt`, `age`, `sex`) VALUES ('%e', '%s', '%e', '%d', '%d')", Player[playerid][Name], Player[playerid][Password], Player[playerid][Salt], Player[playerid][Age], Player[playerid][Sex]);
  269. mysql_tquery(g_SQL, query, "OnPlayerRegister", "d", playerid);
  270. new Messaggio[256];
  271. format(Messaggio, sizeof (Messaggio), "[INFO]: %s sei {0000cc}un uomo", Player[playerid][Name]);
  272. SendClientMessage(playerid, COLOR_SYSTEM_INFO, Messaggio);
  273. }
  274. }
  275. }
  276. default: return 0; // dialog ID was not found, search in other scripts
  277. }
  278. return 1;
  279. }
  280.  
  281. //-----------------------------------------------------
  282.  
  283.  
  284.  
  285. // controllo se una string è numerica
  286. IsNumeric(const string[])
  287. {
  288. for (new i = 0, j = strlen(string); i < j; i++)
  289. {
  290. if (string[i] > '9' || string[i] < '0') return 0;
  291. }
  292. return 1;
  293. }
  294.  
  295. forward OnPlayerDataLoaded(playerid, race_check);
  296. public OnPlayerDataLoaded(playerid, race_check)
  297. {
  298. /* race condition check:
  299. player A connects -> SELECT query is fired -> this query takes very long
  300. while the query is still processing, player A with playerid 2 disconnects
  301. player B joins now with playerid 2 -> our laggy SELECT query is finally finished, but for the wrong player
  302. what do we do against it?
  303. we create a connection count for each playerid and increase it everytime the playerid connects or disconnects
  304. we also pass the current value of the connection count to our OnPlayerDataLoaded callback
  305. then we check if current connection count is the same as connection count we passed to the callback
  306. if yes, everything is okay, if not, we just kick the player
  307. */
  308. if (race_check != g_MysqlRaceCheck[playerid]) return Kick(playerid);
  309.  
  310. new string[115];
  311. if(cache_num_rows() > 0)
  312. {
  313. // we store the password and the salt so we can compare the password the player inputs
  314. // and save the rest so we won't have to execute another query later
  315. cache_get_value(0, "password", Player[playerid][Password], 65);
  316. cache_get_value(0, "salt", Player[playerid][Salt], 17);
  317.  
  318. // saves the active cache in the memory and returns an cache-id to access it for later use
  319. Player[playerid][Cache_ID] = cache_save();
  320.  
  321. format(string, sizeof string, "%s risulta registrato sul server.\nInserisci la password per entrare:", Player[playerid][Name]);
  322. ShowPlayerDialog(playerid, DIALOG_LOGIN, DIALOG_STYLE_PASSWORD, "Login", string, "Login", "Annulla");
  323.  
  324. // from now on, the player has 30 seconds to login
  325. Player[playerid][LoginTimer] = SetTimerEx("OnLoginTimeout", SECONDS_TO_LOGIN * 1000, false, "d", playerid);
  326. }
  327. else
  328. {
  329. format(string, sizeof string, "Benvenuto %s,\nInserisci una password per iniziare la registrazione:", Player[playerid][Name]);
  330. ShowPlayerDialog(playerid, DIALOG_REGISTER, DIALOG_STYLE_PASSWORD, "Registrazione", string, "Continua", "Annulla");
  331. }
  332. return 1;
  333. }
  334.  
  335. forward OnLoginTimeout(playerid);
  336. public OnLoginTimeout(playerid)
  337. {
  338. // reset the variable that stores the timerid
  339. Player[playerid][LoginTimer] = 0;
  340.  
  341. ShowPlayerDialog(playerid, DIALOG_UNUSED, DIALOG_STYLE_MSGBOX, "Login", "Sei stato kickato dal server per aver impiegato troppo tempo nel loggarti.", "Okay", "");
  342. DelayedKick(playerid);
  343. return 1;
  344. }
  345.  
  346. forward OnPlayerRegister(playerid);
  347. public OnPlayerRegister(playerid)
  348. {
  349. // retrieves the ID generated for an AUTO_INCREMENT column by the sent query
  350. Player[playerid][ID] = cache_insert_id();
  351.  
  352. ShowPlayerDialog(playerid, DIALOG_UNUSED, DIALOG_STYLE_MSGBOX, "Registration", "Account successfully registered, you have been automatically logged in.", "Okay", "");
  353.  
  354. Player[playerid][IsLoggedIn] = true;
  355.  
  356. Player[playerid][X_Pos] = DEFAULT_POS_X;
  357. Player[playerid][Y_Pos] = DEFAULT_POS_Y;
  358. Player[playerid][Z_Pos] = DEFAULT_POS_Z;
  359. Player[playerid][A_Pos] = DEFAULT_POS_A;
  360.  
  361. SetSpawnInfo(playerid, NO_TEAM, 0, Player[playerid][X_Pos], Player[playerid][Y_Pos], Player[playerid][Z_Pos], Player[playerid][A_Pos], 0, 0, 0, 0, 0, 0);
  362. SpawnPlayer(playerid);
  363. return 1;
  364. }
  365.  
  366. forward _KickPlayerDelayed(playerid);
  367. public _KickPlayerDelayed(playerid)
  368. {
  369. Kick(playerid);
  370. return 1;
  371. }
  372.  
  373.  
  374. //-----------------------------------------------------
  375.  
  376. AssignPlayerData(playerid)
  377. {
  378. cache_get_value_int(0, "id", Player[playerid][ID]);
  379.  
  380. cache_get_value_int(0, "kills", Player[playerid][Kills]);
  381. cache_get_value_int(0, "deaths", Player[playerid][Deaths]);
  382. cache_get_value_int(0, "admin", Player[playerid][Admin]);
  383. cache_get_value_int(0, "sex", Player[playerid][Sex]);
  384. cache_get_value_int(0, "age", Player[playerid][Age]);
  385. cache_get_value_float(0, "x", Player[playerid][X_Pos]);
  386. cache_get_value_float(0, "y", Player[playerid][Y_Pos]);
  387. cache_get_value_float(0, "z", Player[playerid][Z_Pos]);
  388. cache_get_value_float(0, "angle", Player[playerid][A_Pos]);
  389. cache_get_value_int(0, "interior", Player[playerid][Interior]);
  390. return 1;
  391. }
  392.  
  393. DelayedKick(playerid, time = 500)
  394. {
  395. SetTimerEx("_KickPlayerDelayed", time, false, "d", playerid);
  396. return 1;
  397. }
  398.  
  399. SetupPlayerTable()
  400. {
  401. mysql_tquery(g_SQL, "CREATE TABLE IF NOT EXISTS `players` (`id` int(11) NOT NULL AUTO_INCREMENT,`username` varchar(24) NOT NULL,`password` char(64) NOT NULL,`salt` char(16) NOT NULL,`kills` mediumint(8) NOT NULL DEFAULT '0',`deaths` mediumint(8) NOT NULL DEFAULT '0',`x` float NOT NULL DEFAULT '0',`y` float NOT NULL DEFAULT '0',`z` float NOT NULL DEFAULT '0',`angle` float NOT NULL DEFAULT '0',`interior` tinyint(3) NOT NULL DEFAULT '0', PRIMARY KEY (`id`), UNIQUE KEY `username` (`username`))");
  402. return 1;
  403. }
  404.  
  405. UpdatePlayerData(playerid, reason)
  406. {
  407. if (Player[playerid][IsLoggedIn] == false) return 0;
  408.  
  409. // if the client crashed, it's not possible to get the player's position in OnPlayerDisconnect callback
  410. // 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)
  411. if (reason == 1)
  412. {
  413. GetPlayerPos(playerid, Player[playerid][X_Pos], Player[playerid][Y_Pos], Player[playerid][Z_Pos]);
  414. GetPlayerFacingAngle(playerid, Player[playerid][A_Pos]);
  415. }
  416.  
  417. new query[145];
  418. mysql_format(g_SQL, query, sizeof query, "UPDATE `players` SET `x` = %f, `y` = %f, `z` = %f, `angle` = %f, `interior` = %d WHERE `id` = %d LIMIT 1", Player[playerid][X_Pos], Player[playerid][Y_Pos], Player[playerid][Z_Pos], Player[playerid][A_Pos], GetPlayerInterior(playerid), Player[playerid][ID]);
  419. mysql_tquery(g_SQL, query);
  420. return 1;
  421. }
  422.  
  423. UpdatePlayerDeaths(playerid)
  424. {
  425. if (Player[playerid][IsLoggedIn] == false) return 0;
  426.  
  427. Player[playerid][Deaths]++;
  428.  
  429. new query[70];
  430. mysql_format(g_SQL, query, sizeof query, "UPDATE `players` SET `deaths` = %d WHERE `id` = %d LIMIT 1", Player[playerid][Deaths], Player[playerid][ID]);
  431. mysql_tquery(g_SQL, query);
  432. return 1;
  433. }
  434.  
  435. UpdatePlayerKills(killerid)
  436. {
  437. // we must check before if the killer wasn't valid (connected) player to avoid run time error 4
  438. if (killerid == INVALID_PLAYER_ID) return 0;
  439. if (Player[killerid][IsLoggedIn] == false) return 0;
  440.  
  441. Player[killerid][Kills]++;
  442.  
  443. new query[70];
  444. mysql_format(g_SQL, query, sizeof query, "UPDATE `players` SET `kills` = %d WHERE `id` = %d LIMIT 1", Player[killerid][Kills], Player[killerid][ID]);
  445. mysql_tquery(g_SQL, query);
  446. return 1;
  447. }
  448. //-----------------------------------------------------------------------
  449. // comandi - zcmd
  450.  
  451. CMD:admin(playerid, params[])
  452. {
  453. if(Player[playerid][Admin] == 0)
  454. {
  455. SendClientMessage(playerid, COLOR_SYSTEM_ERROR, "asd");
  456. return 1;
  457. }
  458. else if(Player[playerid][Admin] >= 1)
  459. {
  460. SendClientMessage(playerid, COLOR_SYSTEM_SUCCESS, "123");
  461. return 1;
  462. }
  463. return 1;
  464. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement