Seregamil
Мастер
Добрый день пользователи портала!
Все чаще я стал замечать, что люди пытаются смастерить что-либо на SQLite, но чаще всего это оборачивается крашами, выходами за пределы массивов, левыми запросами и прочей фигней, способствующей поломке сервера.
Сам по себе SQLite (a_sampdb) уже встроен в сервер и не требует никаких манипуляций с плагинами, инклудами и прочими конструкторами.
Для тех, что считает, что SQLite медленная и для сервера она приносит больше вреда, чем пользы - обломитесь, если написать правильно код - все будет работать идеально и без сбоев
Перед использованием SQLite советую почитать мануалы от OFFREAL'a и полазить в википедии, дабы понять как и что устроено.
Пример использования SQLite я покажу на простенькой регистрации, написанной за 10 минут
В начало вашего мода нужно добавить пару переменных и один дефайн:
Переменные DB и DBResult отвечают за саму базу данных и за результат отправки запроса соответственно.
users.db - местоположение вашей базы в папке scriptfiles
Далее перейдем в OnGameModeInit
Тут я полагаю всем все понятно, проверяем на существование и открываем или создаем в зависимости от условия
OnGameModeExit в данном уроке смысла юзать нету, т.к. на люниксе при краше сервера данный каллбэк неработает, но для примера -
Теперь перейдем непосредственно к выдаче диалога игроку при его подключении на сервер
OnPlayerConnect:
Тут я полагаю тоже все понятно, отправили запрос, получили результат, если строк нету - игрока в базе соответственно нету
Это нужно засунуть в конец мода(функция определения имени игрока), у кого есть - настроите сами
При выходе игрока нам требуется сохранить его личные данные
OnPlayerDisconnect
И в конец мода -
Здесь мы обновили данные игрока в базе данных при выходе
Для запрета использования команды, или если игрок решит воспользоваться чатом, при этом ненаходясь в системеиспользуем этот код
OnPlayerCommandText & OnPlayerText
Теперь перейдем непосредственно к диалогам
В OnDialogResponse
В пхп коде я постарался расписать наиболее внятно для всех все действия, которые совершаются
По поводу получение значения из таблицы методом db_get_field_assoc
Есть еще одна функция для получения значений через ID столбика, тут уже кому как удобнее
Лично я привык через название столбца
Ну и финал - в конец мода добавим функцию для проверки пароля
Тут я полагаю тоже все понятно
Вот и все! Для того, чтобы открыть таблицу, используйте программу SQLite Database Browser
Автор урока - Seregamil
И присваиваем к этой переменной результат, далее смотрим на полученный результат
по поводу varchar, int
varchar - это простая строка, проще говоря текст
int - целое число
по поводу float - его можно записывать в виде varchara, а при считывании значений использовать floatstr(куда записало)
UPDATE USERS - обновить таблицу с юзерами
SET... установить то то то то
WHERE NAME - по такому то значению, в нашем случае это имя игрока
Результат нам в этой ситуации не нужен, по этому dbresult и не юзаю
valid_password - проверка на пароль игрока, значения я писал сам, потом расскажу, ну если пароль не подошел под мои критерии - выдаем диалог
Писал сам, поясняю:
!strlen - полностью пустая строка, аля кол-во символов = 0
проверяем символ в пароле,
Все чаще я стал замечать, что люди пытаются смастерить что-либо на SQLite, но чаще всего это оборачивается крашами, выходами за пределы массивов, левыми запросами и прочей фигней, способствующей поломке сервера.
Сам по себе SQLite (a_sampdb) уже встроен в сервер и не требует никаких манипуляций с плагинами, инклудами и прочими конструкторами.
Для тех, что считает, что SQLite медленная и для сервера она приносит больше вреда, чем пользы - обломитесь, если написать правильно код - все будет работать идеально и без сбоев
Перед использованием SQLite советую почитать мануалы от OFFREAL'a и полазить в википедии, дабы понять как и что устроено.
Пример использования SQLite я покажу на простенькой регистрации, написанной за 10 минут
В начало вашего мода нужно добавить пару переменных и один дефайн:
PHP:
new DB: users_base;
new DBResult: u_result;
#define database "users.db"
users.db - местоположение вашей базы в папке scriptfiles
Далее перейдем в OnGameModeInit
PHP:
if(!fexist(database)){//если БД отсутствует
users_base = db_open(database);//функция 'db_open(base[])' при отсутствии нужной нам базы данных создает пустую БД
db_query(users_base,"CREATE TABLE USERS(NAME varchar, PASSWORD varchar, MONEY int, KILLS int)");//ну и как итог - заполним базу данных со столбцами "Name, Password, Money, Kills"
}
else{//если БД присутствует
users_base = db_open(database);//тупо откроем ее
}
OnGameModeExit в данном уроке смысла юзать нету, т.к. на люниксе при краше сервера данный каллбэк неработает, но для примера -
PHP:
for(new i;i!=GetMaxPlayers();i++){
if(IsPlayerConnected(i) && GetPVarInt(i,"logged") == 1 && !IsPlayerNPC(i)){//на сервере, в системе, и не бот
save_user(i);//сохраним
}
}
db_close(users_base);//при окончании работы сервера - закроем базу данных
OnPlayerConnect:
PHP:
new str[500];
format(str,sizeof str,"SELECT NAME, PASSWORD FROM USERS WHERE NAME = '%s'",p_name(playerid));//отправим запрос в таблицу на поиск нужного нам игрока
u_result = db_query(users_base,str);
if(!db_num_rows(u_result)){//если строки по нужному нам запросы отсутствуют в таблице - значит игрок незарегестрирован на сервере
ShowPlayerDialog(playerid, 0, DIALOG_STYLE_INPUT, " ","Зарегестрируйтесь","Вход","Кик");
}
else{//нужная нам строка присутствует
ShowPlayerDialog(playerid, 1, DIALOG_STYLE_INPUT, " ","Войдите в систему","Вход","Кик");
}
PHP:
p_name(playerid){
new name[24];
GetPlayerName(playerid,name,24);
return name;
}
При выходе игрока нам требуется сохранить его личные данные
OnPlayerDisconnect
PHP:
if(GetPVarInt(playerid,"logged") == 1) save_user(playerid);//при выходе игрока - сохраним его, при условии, что он уже вошел в систему
PHP:
save_user(userid){
new str[500];
format(str,500,"UPDATE USERS SET MONEY = '%d', KILLS = '%d' WHERE NAME = '%s'",GetPlayerMoney(userid),GetPlayerScore(userid),p_name(userid));
db_query(users_base, str);//обновим значения денег и убийств в базе для игрока %s
}
Для запрета использования команды, или если игрок решит воспользоваться чатом, при этом ненаходясь в системеиспользуем этот код
OnPlayerCommandText & OnPlayerText
PHP:
if(GetPVarInt(playerid,"logged") == 0) return false;
В OnDialogResponse
PHP:
if(dialogid == 0){
if(!response) return Kick(playerid);//если игрок нажал 'ESC' или нажал на вторую кнопку - пошлем его к чертям
if(!valid_password(inputtext)){//если введен некорректный пароль
return ShowPlayerDialog(playerid, 0, DIALOG_STYLE_INPUT, " ","Зарегестрируйтесь","Вход","Кик");
}
new str[500];
format(str,500,"INSERT INTO `USERS` (`NAME`, `PASSWORD`, `MONEY`, `KILLS`) VALUES ('%s', '%s', '0', '0')", p_name(playerid), inputtext);
db_query(users_base, str);//добавим игрока в таблицу ко всем бабушкам
SetPVarInt(playerid,"logged",1);//установим пивоварку на 1, т.е. игрок вошел в систему
SendClientMessage(playerid,-1,"Вы успешно зарегестрировались на сервере!");
return true;
}
if(dialogid == 1){
if(!response) return Kick(playerid);//если игрок нажал 'ESC' или нажал на вторую кнопку - пошлем его к чертям
if(!valid_password(inputtext)){//если введен некорректный пароль
return ShowPlayerDialog(playerid, 1, DIALOG_STYLE_INPUT, " ","Войдите в систему","Вход","Кик");
}
new str[500];
format(str,500,"SELECT * FROM USERS WHERE NAME = '%s'",p_name(playerid));
u_result = db_query(users_base, str);
new Field[100];
db_get_field_assoc( u_result, "PASSWORD", Field, sizeof( Field ) );//запишем пароль из строки в переменную Field
if(strcmp(Field, inputtext, true) == 0){//если пароли совпали
db_get_field_assoc( u_result, "MONEY", Field, sizeof( Field ) ), GivePlayerMoney(playerid, strval(Field));
db_get_field_assoc( u_result, "KILLS", Field, sizeof( Field ) ), SetPlayerScore(playerid, strval(Field));
SetPVarInt(playerid,"logged",1);//установим пивоварку на 1, т.е. игрок вошел в систему
SendClientMessage(playerid,-1,"Вы успешно вернулись в систему!");
}
else ShowPlayerDialog(playerid, 1, DIALOG_STYLE_INPUT, " ","Войдите в систему","Вход","Кик");
return true;
}
По поводу получение значения из таблицы методом db_get_field_assoc
Есть еще одна функция для получения значений через ID столбика, тут уже кому как удобнее
Лично я привык через название столбца
Чтобы видеть скрытое содержание Зарегистрируйтесь на форуме!
Чтобы видеть скрытое содержание Зарегистрируйтесь на форуме!
Ну и финал - в конец мода добавим функцию для проверки пароля
PHP:
valid_password(password[]){
if(!strlen(password)) return false;//пароль тупо пустой
for(new i;i!=strlen(password);i++){
switch(password[i]){
case 'a'..'z','A'..'Z','0'..'9': continue;//допустимые символы: английская расскладка и цифры
default: return false;//во всех остальных случаях пароль некорректный
}
}
return true;
}
Вот и все! Для того, чтобы открыть таблицу, используйте программу SQLite Database Browser
Автор урока - Seregamil
Отвечает за базу данных и все последующие действия с ней, т.е. открыть, закрыть, послать запрос и прочие действияnew DB: users_base;
переменная получения результата, т.е. если нам нужно получить например строку PASSWORD по имени Seregamil, то мы отправляем запросnew DBResult: u_result;
PHP:
SELECT PASSWORD FROM USERS WHERE NAME = 'Seregamil'
Открывает базу данных, если БД не существует, то создастся пустая база данныхusers_base = db_open(database);
Здесь у нас БД отсутствует и мы ее заполняем, т.е. создаем запрос на создание таблицы USERS со столбцами NAME, PASSWORD, MONEY, KILLS,так же есть запрос CREATE TABLE IF NOT EXIST - создать базу если она не существует, но его редко используютdb_query(users_base,"CREATE TABLE USERS(NAME varchar, PASSWORD varchar, MONEY int, KILLS int)");
по поводу varchar, int
varchar - это простая строка, проще говоря текст
int - целое число
по поводу float - его можно записывать в виде varchara, а при считывании значений использовать floatstr(куда записало)
Прогоняет по всем игрокам, проверяет, подключен ли игрок, а так же в системе ли он, и проверяет, если он не бот - сохраняет данные игрокаfor(new i;i!=GetMaxPlayers();i++){
if(IsPlayerConnected(i) && GetPVarInt(i,"logged") == 1 && !IsPlayerNPC(i)){//на сервере, в системе, и не бот
save_user(i);//сохраним
}
}
закрываем БДdb_close(users_base);
Как я и говорил - послал запрос, приравнял его к переменнойnew str[500];
format(str,sizeof str,"SELECT NAME, PASSWORD FROM USERS WHERE NAME = '%s'",p_name(playerid));//отправим запрос в таблицу на поиск нужного нам игрока
u_result = db_query(users_base,str);
получил ответ от запроса, db_num_rows подсчитывает кол-во строк в запросе, если аккаунт игрока есть - будет как минимум 1 строка, если нету - 0 строкif(!db_num_rows(u_result)){//если строки по нужному нам запросы отсутствуют в таблице - значит игрок незарегестрирован на сервере
ShowPlayerDialog(playerid, 0, DIALOG_STYLE_INPUT, " ","Зарегестрируйтесь","Вход","Кик");
}
else{//нужная нам строка присутствует
ShowPlayerDialog(playerid, 1, DIALOG_STYLE_INPUT, " ","Войдите в систему","Вход","Кик");
}
Сохранение пользователяsave_user(userid){
new str[500];
format(str,500,"UPDATE USERS SET MONEY = '%d', KILLS = '%d' WHERE NAME = '%s'",GetPlayerMoney(userid),GetPlayerScore(userid),p_name(userid));
db_query(users_base, str);//обновим значения денег и убийств в базе для игрока %s
}
UPDATE USERS - обновить таблицу с юзерами
SET... установить то то то то
WHERE NAME - по такому то значению, в нашем случае это имя игрока
Результат нам в этой ситуации не нужен, по этому dbresult и не юзаю
Если игрок тыкнул ESC или кнопку кик - кикаем егоif(!response) return Kick(playerid);//если игрок нажал 'ESC' или нажал на вторую кнопку - пошлем его к чертям
if(!valid_password(inputtext)){//если введен некорректный пароль
return ShowPlayerDialog(playerid, 0, DIALOG_STYLE_INPUT, " ","Зарегестрируйтесь","Вход","Кик");
}
valid_password - проверка на пароль игрока, значения я писал сам, потом расскажу, ну если пароль не подошел под мои критерии - выдаем диалог
INSERT INTO - добавляет строку в нужную вам таблицу, в данном случае - в таблицу с игроками в новую строку под столбцами NAME, PASSWORD, MONEY, KILLS добавит имя, пароль, 0, 0 соответственноnew str[500];
format(str,500,"INSERT INTO `USERS` (`NAME`, `PASSWORD`, `MONEY`, `KILLS`) VALUES ('%s', '%s', '0', '0')", p_name(playerid), inputtext);
db_query(users_base, str);//добавим игрока в таблицу ко всем бабушкам
Это уже авторизация, перед проверкой пароля достанем верный пароль из таблицы и запишем его в переменную Fieldnew Field[100];
db_get_field_assoc( u_result, "PASSWORD", Field, sizeof( Field ) );//запишем пароль из строки в переменную Field
Проверка на совпадение строк верного пароля в переменной Field и пароля, введенного игрокомif(strcmp(Field, inputtext, true) == 0)
Получаем данные столбца MONEY и записываем опять в переменную Field, далее в GivePlayerMoney преобразуем строку Field в целочисленное значение через strvaldb_get_field_assoc( u_result, "MONEY", Field, sizeof( Field ) ), GivePlayerMoney(playerid, strval(Field));
valid_password(password[]){
if(!strlen(password)) return false;//пароль тупо пустой
for(new i;i!=strlen(password);i++){
switch(password){
case 'a'..'z','A'..'Z','0'..'9': continue;//допустимые символы: английская расскладка и цифры
default: return false;//во всех остальных случаях пароль некорректный
}
}
return true;
}
Писал сам, поясняю:
!strlen - полностью пустая строка, аля кол-во символов = 0
пошли по длине пароляfor(new i;i!=strlen(password);i++){
switch(password){
проверяем символ в пароле,
если этот символ является английским, неважно, какого регистра, или символ - цифра - продолжим проверятьcase 'a'..'z','A'..'Z','0'..'9':
в противном случае - пароль неверныйdefault: return false;
Последнее редактирование:
