Перейти к содержанию

Поиск сообщества

Показаны результаты для тегов 'ALL'.

  • Поиск по тегам

    Введите теги через запятую.
  • Поиск по автору

Тип контента


Форумы

  • Информационный раздел
    • Новости портала
    • Техническая поддержка
    • Приватный форум
  • CRMP 0.3е
    • Помощь по Скриптингу
    • Ошибки
    • Готовые сервера
    • Дополнительные скрипты
    • Мануалы/Уроки
    • Модификации
    • Поиск
    • Архив Вопросов/Проблем/Ошибок
    • Файловый архив
    • Другое
  • SAMP/CRMP 0.3.7
    • Помощь по Скриптингу
    • Ошибки
    • Готовые сервера
    • Плагины
    • Поиск
    • Документация
  • Другое
    • Флейм

Поиск результатов в...

Поиск результатов, которые содержат...


Дата создания

  • Начало

    Конец


Дата обновления

  • Начало

    Конец


Фильтр по количеству...

Найдено: 2 результата

  1. Доброго времени суток. Данный материал прежде всего предназначен для RP/RPG-серверов, однако если будет использоваться где-то еще - спорить не буду. Итак, небольшое вступление. На некоторых серверах существуют правила для ника игрока. Самый яркий пример - РП-сервера, где ник обычно требуют в формате %name%_%surname%. Более того, кое-где существует запрет на регистрацию с ником, имя в котором указано в уменьшительно-ласкательной или иной, отличной от официальной, формы (Sasha вместо Alexander и так далее). При достаточно большом количестве игроков уследить за подобными случаями становится все сложнее. Но, как говорится, "кто ищет - тот всегда найдет!" Перед скриптом ставились следующие задачи: Хранить где-то базу некорректных ников. Это показалось проще, чем вести базу корректных. Иметь удобные инструменты для добавления, удаления и проверки наличия записи. Не допускать игрока к серверу в случае совпадения имени с базой и отключать от сервера в случае добавления новой записи в базу. Первую задачу решено было решить, используя SQLite. Создавать что-то на файлах показалось мне не слишком удобным в реализации, а на MySQL такую ерунду делать не хотелось. Хотя можно и ее использовать, но зачем, если, по сути, нам нужна только одна колонка в БД? Вторая решилась еще тривиальнее - три команды-три запроса к базе. Еще один запрос - в момент подключения. Но - обо всем по порядку. Итак, для начала необходимо подключить нужные библиотеки. В нашем случае - a_samp и a_sampdb. #include <a_samp> #include <a_sampdb> Для удобства забьем имя файла с базой как директиву препроцессора. #define db_name "WrongNicks.db" Далее - создаем переменную типа DB для хранения указателя на открытую базу и переменную типа DBResult для хранения возвращаемых из базы результатов. new DB:NicksDB; new DBResult:Result; Начнем с загрузки самой базы. Я использовал код в отдельном ФС, однако ничто не мешает зашить его в гейммод. Первоначально с помощью команды db_open открываем файл, имя которого забито в db_name. Или создаем, если он не был создан: NicksDB = db_open(db_name); Далее - делаем запрос в базу. Необходимо, если таблицы Nicks не существует - создать ее с одной колонкой NICK типа varchar - символьной строки. Делается это простым запросом: db_query(NicksDB,"CREATE TABLE IF NOT EXISTS Nicks (NICK varchar)"); Проверять отдельно, есть ли таблица в файле и есть ли файл вообще, нет необходимости, как нет необходимости и в дальнейших действиях при загрузке ГМ или ФС. Конечный код в случае ФС будет выглядеть так: public OnFilterScriptInit() { NicksDB = db_open(db_name); db_query(NicksDB,"CREATE TABLE IF NOT EXISTS Nicks (NICK varchar)"); return 1; } После выгрузки ГМ или ФС базу нужно корректно закрыть. Тут все еще проще - db_close(). public OnFilterScriptExit () { db_close(NicksDB); return 1; } Далее я решил начать с реализации проверки на наличие ника в базе и, соответственно, запрещению доступа к серверу, если ник в базе есть. Алгоритм действий таков: Получаем ник игрока. Это достаточно просто, есть стандартная функция GetPlayerName(), описывать ее я смысла не вижу. Выделение из ника имени и фамилии. Обычно разделителем выступает нижняя черта - ее проверять и будем. Берем с SA:MP Wiki функцию split: stock split(const strsrc[], strdest[][], delimiter) { new i, li; new aNum; new len; while(i <= strlen(strsrc)) { if(strsrc[i] == delimiter || i == strlen(strsrc)) { len = strmid(strdest[aNum], strsrc, li, i, 128); strdest[aNum][len] = 0; li = i+1; aNum++; } i++; } return 1; } Создаем двумерный массив для хранения имени и фамилии и записываем в его элементы отдельно имя и отдельно фамилию, полученные после работы split(). Запрос в базу на наличие ника. Проверка организована просто - в базу посылается запрос, в ответе проверяем, сколько строк вернула база. Если не ноль - значит, записи есть и ник запрещен, а значит - игрока нужно кикнуть. Если ноль - записи нет, ник разрешен, ничего с игроком делать не нужно. Берем OnPlayerConnect и производим все необходимые действия по алгоритму: public OnPlayerConnect (playerid) { new Nick[MAX_PLAYER_NAME];//Получение ника GetPlayerName (playerid, Nick, MAX_PLAYER_NAME); new Name[2][24];//Получение имени и "остатков" split (Nick, Name, '_'); new query [512];//Отсылка запроса к БД format (query, sizeof(query), "SELECT * FROM Nicks WHERE NICK LIKE '%s'", Name[0]); Result = db_query (NicksDB, query);//и прием результата запроса. if (db_num_rows(Result))//Если строк результата больше, чем ноль - запись есть! { new Response[144]; SendClientMessage (playerid, 0xdc143cFF, "Вы были кикнуты сервером. Причина: В нике указано неполное имя."); Kick(playerid); format (Response, sizeof(Response), "Игрок %s кикнут сервером. Причина: В нике указано неполное имя.", Nick); SendClientMessageToAll (0xdc143cFF, Response); } return 1; } Хочу обратить внимание на сам запрос в БД: SELECT * FROM Nicks WHERE NICK LIKE '%s'Оператор LIKE здесь используется как оператор нестрогого сравнения - то есть регистр символов может не совпадать. Однако с русскими символами в строке такой запрос не пройдет, что в MySQL, что в SQLite придется городить костыли. У меня не используются ники с русскими символами, поэтому меня такой запрос вполне устраивает в текущем виде. Ну и осталось, собственно, только организовать удобство работы с такой базой. Поскольку бросать идею не хотелось, а использовать для такого порыва покодить какие-то сторонние тулзы вроде командных процессоров было откровенно лень - все построено на стандартной функции OnPlayerCommandText и ненавистной многими strtok: strtok(const string[], &index) { new length = strlen(string); while ((index < length) && (string[index] <= ' ')) { index++; } new offset = index; new result[20]; while ((index < length) && (string[index] > ' ') && ((index - offset) < (sizeof(result) - 1))) { result[index - offset] = string[index]; index++; } result[index - offset] = EOS; return result; } Однако, конечно, если захотите использовать другой командный процессор - пожалуйста, перетаскивайте. Начнем с команды добавления записи в базу и одновременной проверки игроков на свежедобавленное имя. Алгоритм прост - из строки cmdtext получаем необходимый параметр и делаем запрос к базе, после чего циклом проверяем все имена игроков, полученные split(). Далее код с комментариями, который, конечно, нужно пихнуть в OnPlayerCommandText, в котором уже объявлены нужные переменные для strtok: //Для strtok new cmd[256], tmp[256], idx; cmd = strtok(cmdtext, idx); if (!strcmp ("/addnick", cmd, true)) { if (!IsPlayerAdmin(playerid)) //Если игрок не RCon - доступ к функции не даем. { SendClientMessage (playerid, 0xdc143cFF, "Вы не обладаете необходимыми правами доступа."); return 1; } tmp = strtok(cmdtext, idx); if (!strlen(tmp)) //Если параметр пустой - выводим сообщение об ошибке. { SendClientMessage (playerid, 0xdc143cFF, "Синтаксис команды: /addnick [Имя]"); return 1; } new query[512]; //Делаем запрос в базу. format (query, sizeof(query), "INSERT INTO Nicks (NICK) VALUES ('%s')", tmp); db_query (NicksDB, query); SendClientMessage (playerid, 0xdc143cFF, "Ник добавлен в базу данных."); //..и оповещаем об этом пользователя. new TempNick[MAX_PLAYER_NAME]; //Готовим переменную под ник. for (new pid=0; pid<MAX_PLAYERS; pid++) //Для всех игроков { if (IsPlayerConnected(pid)) //Если проверяемый подключен - { GetPlayerName (pid, TempNick, MAX_PLAYER_NAME); //получаем его ник полностью if (!strcmp (TempNick, tmp, true, strlen(tmp))) //и проверяем на соответствие с новой записью - вне зависимости от регистра и только количество символов, которое было в новой записи! { //Если условия соблюдены - выбрасываем игрока с сервера. Войти обратно ему не даст код в OnPlayerConnect. new Response[144]; SendClientMessage (pid, 0xdc143cFF, "Вы были кикнуты сервером. Причина: В нике указано неполное имя."); Kick(pid); format (Response, sizeof(Response), "Игрок %s кикнут сервером. Причина: В нике указано неполное имя.", TempNick); SendClientMessageToAll (0xdc143cFF, Response); } } } return 1; } Похожая ситуация - с удалением записи. Даже если похожей записи нет - запрос ничего лишнего не удалит, поэтому на проверку наличия в базе можно не заморачиваться. if (!strcmp ("/removenick", cmd, true)) { if (!IsPlayerAdmin(playerid)) { SendClientMessage (playerid, 0xdc143cFF, "Вы не обладаете необходимыми правами доступа."); return 1; } tmp = strtok(cmdtext, idx); if (!strlen(tmp)) { SendClientMessage (playerid, 0xdc143cFF, "Синтаксис команды: /removenick [Имя]"); return 1; } new query[512]; format (query, sizeof(query), "DELETE FROM Nicks WHERE NICK LIKE '%s'", tmp); //Запрос на удаление строк с похожим значением. db_query (NicksDB, query); SendClientMessage (playerid, 0xdc143cFF, "Ник удален из базы данных."); return 1; } В конкретном случае вместо строгого сравнения в запросе опять используется оператор LIKE. Ну, и функция проверки на наличие записи. Тут все аналогично проверке в OnPlayerConnect - если запрос вернет более нуля строк как результат, значит, запись есть. В противном случае - нет. if (!strcmp ("/checknick", cmd, true)) { if (!IsPlayerAdmin(playerid)) { SendClientMessage (playerid, 0xdc143cFF, "Вы не обладаете необходимыми правами доступа."); return 1; } tmp = strtok(cmdtext, idx); if (!strlen(tmp)) { SendClientMessage (playerid, 0xdc143cFF, "Синтаксис команды: /checknick [Имя]"); return 1; } new query[512]; format (query, sizeof(query), "SELECT * FROM Nicks WHERE NICK LIKE '%s'", tmp); Result = db_query (NicksDB, query); if (db_num_rows(Result)) SendClientMessage (playerid, 0xdc143cFF, "Данное имя есть в базе данных запрещенных имен."); else SendClientMessage (playerid, 0xdc143cFF, "Данного имени в базе запрещенных имен нет."); return 1; } На этом все! Система работоспособна и готова к наполнению невалидными никами. #define FILTERSCRIPT #define db_name "WrongNicks.db" #include <a_samp> #include <a_sampdb> new DB:NicksDB; new DBResult:Result; public OnFilterScriptInit() { NicksDB = db_open(db_name); db_query(NicksDB,"CREATE TABLE IF NOT EXISTS Nicks (NICK varchar)"); return 1; } public OnFilterScriptExit () { db_close(NicksDB); return 1; } public OnPlayerConnect (playerid) { new Nick[MAX_PLAYER_NAME]; GetPlayerName (playerid, Nick, MAX_PLAYER_NAME); new Name[2][24]; split (Nick, Name, '_'); new query [512]; format (query, sizeof(query), "SELECT * FROM Nicks WHERE NICK LIKE '%s'", Name[0]); Result = db_query (NicksDB, query); if (db_num_rows(Result)) { new Response[144]; SendClientMessage (playerid, 0xdc143cFF, "Вы были кикнуты сервером. Причина: В нике указано неполное имя."); Kick(playerid); format (Response, sizeof(Response), "Игрок %s кикнут сервером. Причина: В нике указано неполное имя.", Nick); SendClientMessageToAll (0xdc143cFF, Response); } return 1; } public OnPlayerCommandText (playerid, cmdtext[]) { new cmd[256], tmp[256], idx; cmd = strtok(cmdtext, idx); if (!strcmp ("/addnick", cmd, true)) { if (!IsPlayerAdmin(playerid)) { SendClientMessage (playerid, 0xdc143cFF, "Вы не обладаете необходимыми правами доступа."); return 1; } tmp = strtok(cmdtext, idx); if (!strlen(tmp)) { SendClientMessage (playerid, 0xdc143cFF, "Синтаксис команды: /addnick [Имя]"); return 1; } new query[512]; format (query, sizeof(query), "INSERT INTO Nicks (NICK) VALUES ('%s')", tmp); db_query (NicksDB, query); SendClientMessage (playerid, 0xdc143cFF, "Ник добавлен в базу данных."); new TempNick[MAX_PLAYER_NAME]; for (new pid=0; pid<MAX_PLAYERS; pid++) { if (IsPlayerConnected(pid)) { GetPlayerName (pid, TempNick, MAX_PLAYER_NAME); if (!strcmp (TempNick, tmp, true, strlen(tmp))) { new Response[144]; SendClientMessage (pid, 0xdc143cFF, "Вы были кикнуты сервером. Причина: В нике указано неполное имя."); Kick(pid); format (Response, sizeof(Response), "Игрок %s кикнут сервером. Причина: В нике указано неполное имя.", TempNick); SendClientMessageToAll (0xdc143cFF, Response); } } } return 1; } if (!strcmp ("/removenick", cmd, true)) { if (!IsPlayerAdmin(playerid)) { SendClientMessage (playerid, 0xdc143cFF, "Вы не обладаете необходимыми правами доступа."); return 1; } tmp = strtok(cmdtext, idx); if (!strlen(tmp)) { SendClientMessage (playerid, 0xdc143cFF, "Синтаксис команды: /removenick [Имя]"); return 1; } new query[512]; format (query, sizeof(query), "DELETE FROM Nicks WHERE NICK LIKE '%s'", tmp); db_query (NicksDB, query); SendClientMessage (playerid, 0xdc143cFF, "Ник удален из базы данных."); return 1; } if (!strcmp ("/checknick", cmd, true)) { if (!IsPlayerAdmin(playerid)) { SendClientMessage (playerid, 0xdc143cFF, "Вы не обладаете необходимыми правами доступа."); return 1; } tmp = strtok(cmdtext, idx); if (!strlen(tmp)) { SendClientMessage (playerid, 0xdc143cFF, "Синтаксис команды: /checknick [Имя]"); return 1; } new query[512]; format (query, sizeof(query), "SELECT * FROM Nicks WHERE NICK LIKE '%s'", tmp); Result = db_query (NicksDB, query); if (db_num_rows(Result)) SendClientMessage (playerid, 0xdc143cFF, "Данное имя есть в базе данных запрещенных имен."); else SendClientMessage (playerid, 0xdc143cFF, "Данного имени в базе запрещенных имен нет."); return 1; } return 0; } //Разделение stock split(const strsrc[], strdest[][], delimiter) { new i, li; new aNum; new len; while(i <= strlen(strsrc)) { if(strsrc[i] == delimiter || i == strlen(strsrc)) { len = strmid(strdest[aNum], strsrc, li, i, 128); strdest[aNum][len] = 0; li = i+1; aNum++; } i++; } return 1; } strtok(const string[], &index) { new length = strlen(string); while ((index < length) && (string[index] <= ' ')) { index++; } new offset = index; new result[20]; while ((index < length) && (string[index] > ' ') && ((index - offset) < (sizeof(result) - 1))) { result[index - offset] = string[index]; index++; } result[index - offset] = EOS; return result; } Исходник также доступен на пастбине. Данное решение, возможно, не является суперсовершенным и суперфункциональным, но то, чего я хотел - я добился. Все работает, и работает как надо. Вопросы и пожелания принимаются ниже.
  2. Amfy

    Раздевалка

    Собственно в названии темы всё понятно. Простая раздевалка для РП сервера. if(strcmp("/clothes", cmdtext, true, 10) == 0)//Команда{if(!IsPlayerInRangeOfPoint(playerid, 1.0, X, Y, Z)) return SendClientMessage(playerid, -1, "Вы должны быть в раздевалке!");//X, Y, Z замените на свои координатыif(GetPVarInt(playerid, "CLOTHES") != 1)//Если CLOTHES не равен одному - надевает форму{SendClientMessage(playerid, -1, "Вы надели служебную форму.");//ТекстSetPVarInt(playerid, "SKIN", GetPlayerSkin(playerid));//Записывает скин в переменную SKINSetPlayerSkin(playerid, 280);//Выдает новый скинSetPVarInt(playerid, "CLOTHES", 1);//CLOTHES становится равен одномуreturn 1;//Удачно}else//Если CLOTHES равен одному - снимает форму{SendClientMessage(playerid, -1, "Вы надели гражданскую одежду.");//ТекстSetPlayerSkin(playerid, GetPVarInt(playerid, "SKIN"));//Выдает скин из переменной SKINDeletePVar(playerid, "CLOTHES");//Удаляет переменную CLOTHESreturn 1;//Удачно}} P.S Табуляция не много попортилась..Автор: Amfy
×

Важная информация

Мы разместили cookie-файлы на ваше устройство, чтобы помочь сделать этот сайт лучше. Вы можете изменить свои настройки cookie-файлов, или продолжить без изменения настроек.