Привет, *user*.
Тутор о том, как не убить свой сервер, выдавая рандомный номер телефона.
Часто в модах вижу подобный код:
- Рандом 6-ти чисел
- Запрос в базу, узнает не совпадает ли номер с уже существующим
- Если совпадает - повторить
Тем самым эта рекурсия может повторяться бесконечное(почти) кол-во раз и привести к зависанию сервера. Напомню, что в сампе 1 поток, поэтому зависнет не у одного игрока, получающего телефон, а у всех.
Есть 2 варианта решения:
- Выдавать номера по порядку
- Выбирать номер из списка номеров
С первым вариантом проблем нет, кроме той, что номер будет не рандомный, но так же не пойдет, ТРУРП без рандомных телефонов КАК ТАК?? Онлайна не будет, 2-ух недельный пиар коту под хвост..кхм, о чем это я.
Значит нужен список, но где его взять? Ответ прост, создать таблицу со всеми возможными номерами (это проще чем звучит :bf
Для начала создаем таблицу:
PHP код:
CREATE TABLE IF NOT EXISTS `phones` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`Number` varchar(6) NOT NULL,
`Player` int(11) NOT NULL DEFAULT '-1',
PRIMARY KEY (`ID`),
UNIQUE KEY `Number` (`Number`,`Player`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
В `Player` будет записываться ID из таблицы с инфой о игроках. Это нужно для того, чтоб пометить занят номер или свободен, в принципе можно просто ставить флаг true/false, но ID игрока может пригодиться для поиска его данных по номеру телефона.
Теперь нужно заполнить таблицу номерами, выполняем SQL запрос:
PHP код:
DELIMITER //
CREATE PROCEDURE lol()
begin
DECLARE i INT DEFAULT 999999;
WHILE i>0 DO
INSERT INTO `phones` SET `Number` = LPAD(i,6,'00000');
SET i=i-1;
END WHILE;
end //
call lol()
В таблице будет 999999 номеров, это более чем достаточно.
Переходим к самой выдаче рандомного номера:
PHP код:
..//При получении номера playerid'ом
mysql_tquery(connectionHandle, "SELECT `ID`, `Number` FROM `phones` WHERE `Player` = -1 ORDER BY RAND() LIMIT 1", "OnGetPhoneNumber", "d", playerid);
..
//Куда-нибудь вниз
forward OnGetPhoneNumber(playerid);
public OnGetPhoneNumber(playerid){
cache_get_row(0, 1, PlayerInfo[playerid][pPhone], connectionHandle, 7);
new query[64];
format(query, sizeof query, "UPDATE `phones` SET `Player` = '%d' WHERE `ID` = '%d' LIMIT 1", PlayerInfo[playerid][pID], cache_get_row_int(0, 0, connectionHandle));
mysql_query(connectionHandle, query, false);
format(query, sizeof query, "Ваш новый номер: %s", PlayerInfo[playerid][pPhone]);
SendClientMessage(playerid, -1, query);
return true;
}
Из всей таблицы выберется 1 номер, где Player равен -1 (не занят), после чего в Player запишется ID игрока(PlayerInfo[playerid][pID]), в PlayerInfo[playerid][pPhone] запишется новый номер.
Если нужно забрать номер у игрока, sql запрос будет следующий:
PHP код:
new str[150];
format(query, sizeof query, "UPDATE `phones` SET `Player` = '-1' WHERE `ID` = (SELECT a.`ID` FROM (SELECT `ID` FROM `phones` WHERE `Number` = '%s' LIMIT 1) as `a`) LIMIT 1", PlayerInfo[playerid][pPhone]);
mysql_query(connectionHandle, query, false);
PlayerInfo[playerid][pPhone][0] = 0x0;
После выполнения в столбец Player установится значение -1(тем самым номер свободен и снова будет участвовать в рандоме), а переменная игрока очистится.
Важно:
- Переменные PlayerInfo[playerid][pPhone](номер с типом стринг), PlayerInfo[playerid][pID](id игрока в базе), connectionHandle(id коннекта к базе) нужно заменить на свои
PHP код:
enum lal{
pID,
pPhone[7]
}
new PlayerInfo[MAX_PLAYERS][lal];
- В уроке нет кода сохранения/загрузки номера в аккаунт, это уже должно быть сделано. Урок написан с учетом наличия в моде сис-мы регистрации на mysql.
- Урок не нацелен на объяснение SQL ф-ий, для этого есть гугл

- Использовался mysql plugin версии R39-4
Ну вот и все, думаю кому-нибудь будет полезно (: