Доброго времени суток. Совсем недавно я принялся изучать язык программирования Lua и примерно за неделю, с трудом написал простенькую, но работоспособную регистрацию на плагине MySQL с примером загрузки информации игрока из базы данных. И так, приступим, постараюсь объяснить детально то, что самому известно.

Скриншот

http://s020.radikal.ru/i708/1602/3e/15c2d98d87b7.png

Вот что реализовано в системе:
1. Регистрация и авторизация, в обоих случаях придётся вводить только лишь логин и пароль.
2. Загрузка данных игрока из базы данных, я решил сделать последнюю позицию игрока, а так - же спавн по ней.
3. Обновление последней позиции игрока и спавн по ней.
4. Авторизация/регистрация проходит не по логину, который в клиенте у игрока, а по логину который введен в окне. (Например был ник "Player111", а в базе данных был аккаунт с ником "Player222", и если игрок "Player111" авторизовался под логином "Player222" то его логин сменится и он будет играть под введенным логином.

Подготовка к написанию самой системы:
Как установить плагин MySQL объяснять думаю не нужно, на Wiki MTA всё доходчиво объяснено.

После установки плагина, приступим к созданию таблицы в базе данных. Структура таблицы "players" для аккаунтов на скриншоте ниже:
http://s017.radikal.ru/i438/1602/3a/fae26c874184.png

Сделали? Отлично, продолжим. Т.к регистрация и авторизация писалась полностью на чистом ресурсе.
Tо идём в папку где находятся все ресурсы (MTA San Andreas 1.5\server\mods\deathmatch\resources) и создаем там новую папку, в которой будут находится наши файлы.

Приступаем к написанию самой системы.

В папке с нашим ресурсом создаем первый файл - meta.xml, и добавляем туда следующие строки:

Код:
<meta>
<script src="server.lua" type="server"/> //Серверная часть ресурса
<script src="client.lua" type="client"/> //Клиентская часть ресурса
</meta>

Дальше мы создаем файл client.lua, в котором будет написана клиентская часть ресурса, и в нём же сейчас пишем следующий код:

Код:
//Первым делом создаем переменные, необходимые для создания GUI окна регистрации и авторизации.
local Window = {}
local TabPanel = {}
local Tab = {}
local Button = {}
local Edit = {}
local Label = {}

Сразу после переменных, переходим к созданию первой функции - создания GUI окна. После переменных добавляем:

Код:
local function createGui()
//Тут скоро мы продолжим писать код.
end

addEventHandler("onClientResourceStart", getResourceRootElement(), function()
    createGui() //Создаем окно с авторизацией и регистрацией.
end)

Теперь внутрь функции createGui, добавляем следующий код:

Код:
//Создаем переменные, определяющие положение окна с регистрацией/авторизацией.
local sWidth, sHeight = guiGetScreenSize()
    local Width,Height = 370,219 
    local X = (sWidth/2) - (Width/2) 
    local Y = (sHeight/2) - (Height/2) 
    Window[1] = guiCreateWindow(X, Y, Width, Height, "Информационное окно",false) //Создаем само окно, где будут расположены все элементы (текста, панели, кнопки и прочее)
    TabPanel[1] = guiCreateTabPanel(9,22,352,188,false, Window[1]) //Создаем TabPanel, на которой и будут расположены кнопки, с помощью которых можно будет переключаться между регистрацией и авторизацией.

//GUI элементы авторизации.
    Tab[1] = guiCreateTab("Авторизация", TabPanel[1])
    Edit[1] = guiCreateEdit(77,10,160,28,"",false,Tab[1]) //Создаем поле для ввода логина.
guiEditSetMaxLength (Edit[1], 22) //Устанавливаем максимальную длину введенного в поле текста - 22 символа.
    Label[1] = guiCreateLabel(9,15,88,30,"Логин:",false,Tab[1]) //Создаем текст левее поля для ввода логина.
        guiSetFont(Label[1],"default-bold-small") //Устанавливаем шрифт для текста выше.
    Edit[2] = guiCreateEdit(77,45,160,28,"",false,Tab[1]) //Создаем поле для ввода пароля.
guiEditSetMaxLength (Edit[2], 30) //Устанавливаем максимальную длину введенного в поле текста - 30 символа.
    Label[2] = guiCreateLabel(9,50,88,30,"Пароль:",false,Tab[1]) //Создаем текст левее поля для ввода пароля.
    guiSetFont(Label[2],"default-bold-small") //Устанавливаем шрифт для текста выше.
    Button[1] = guiCreateButton(97,80,112,29,"Авторизоваться",false,Tab[1]) //После всех элементов выше, создаем кнопку.

//GUI элементы регистрации.
    Tab[2] = guiCreateTab("Регистрация",TabPanel[1])
    Edit[3] = guiCreateEdit(77,10,160,28,"",false,Tab[2]) //Создаем поле для ввода логина.
guiEditSetMaxLength (Edit[3], 22) //Устанавливаем максимальную длину введенного в поле текста - 22 символа.
    Label[3] = guiCreateLabel(9,15,88,30,"Логин:",false,Tab[2]) //Создаем текст левее поля для ввода логина.
    guiSetFont(Label[3],"default-bold-small") //Устанавливаем шрифт для текста выше.
    Edit[4] = guiCreateEdit(77,45,160,28,"",false,Tab[2]) //Создаем поле для ввода пароля.
guiEditSetMaxLength (Edit[4], 30) //Устанавливаем максимальную длину введенного в поле текста - 30 символа.
    Label[4] = guiCreateLabel(9,50,88,30,"Пароль:",false,Tab[2]) //Создаем текст левее поля для ввода пароля.
    guiSetFont(Label[4],"default-bold-small") //Устанавливаем шрифт для текста выше.
    Button[2] = guiCreateButton(92,80,130,29,"Зарегистрироваться",false,Tab[2]) //Создаем кнопку.

    showCursor(true) //Показываем курсор.

    addEventHandler("onClientGUIClick", Button[1], function() //Событие, которое будет происходить при нажатии на кнопку авторизации.
        local text1, text2 = guiGetText(Edit[1]), guiGetText(Edit[2]) //Записываем в 2 переменные введенный текст в поля логина и пароля.
        if(text1 == "") or (text2 == "") then return end //Если поле для ввода логина или пароля пустое - то событие дальше не происходит.
        triggerServerEvent("onPlayerLoginEx", getLocalPlayer(), text1, text2) //Вызываем серверное событие с двумя параметрами - логин, пароль.
    end, false)

    addEventHandler("onClientGUIClick", Button[2], function() //Событие, которое будет происходить при нажатии на кнопку регистрации.
        local text1, text2 = guiGetText(Edit[3]), guiGetText(Edit[4])//Записываем в 2 переменные введенный текст в поля логина и пароля.
        if(text1 == "") or (text2 == "") then return end //Если поле для ввода логина или пароля пустое - то событие дальше не происходит.
        triggerServerEvent("onPlayerRegisterEx", getLocalPlayer(), text1, text2) //Вызываем серверное событие с двумя параметрами - логин, пароль.
    end, false)

После всего выше написанного, добавляем последнее в клиентскую часть:

Код:
addEvent("destroyGui", true)
addEventHandler("destroyGui", getRootElement(), function() //Эта функция пригодится позже, после успешной авторизации или регистрации, для скрытия окна и курсора.
        destroyElement(Window[1]) //Удаляем окно с регистрацией и авторизацией.
        showCursor(false) //Скрываем курсор.
end)

С клиентской частью закончили. Теперь создаем server.lua и добавляем туда следующий код:

Код:
database = mysql_connect("хостинг", "пользователь", "пароль", "название базы данных") //Переменная с подключением к базе данных, настраивайте сами под себя.

После соединения с базой данных, создадим функцию onPlayerLoginEx, которая будет срабатывать когда вы будете нажимать на кнопку авторизации.
И внутри которой будут проходить все проверки на наличие аккаунта.

Код:
addEvent('onPlayerLoginEx', true)
addEventHandler("onPlayerLoginEx", getRootElement(), function(name, password) //Создаем функцию
    local result = mysql_query(database, "SELECT * FROM players WHERE Name = '"..name.."' AND Password = '"..password.."';") //Запрос на проверку наличие аккаунта, по введенным в клиентской части данным (Логин, пароль).
    if(result and mysql_num_rows(result) > 0) then //Если аккаунт такой существует, то идём дальше.
        triggerClientEvent(source, "destroyGui", source) //Вызываем клиентскую функцию, которая удаляет окно и курсор с экрана.
        setPlayerName(source, name) //Устанавливаем игроку имя, введенное в окно логина.
        local row = mysql_fetch_assoc(result)
        setElementData(source, "posX", (row['X'])) //Из поля 'X' в базе данных получаем значение и записываем его в ключ "posX' на сервере.
        setElementData(source, "posY", (row['Y'])) //Из поля 'Y' в базе данных получаем значение и записываем его в ключ "posY' на сервере.
        setElementData(source, "posZ", (row['Z'])) //Из поля 'Z' в базе данных получаем значение и записываем его в ключ "posZ' на сервере.
        spawnPlayer(source, getElementData(source, "posX"), getElementData(source, "posY"), getElementData(source, "posZ")) //Спавним игрока, по загруженным выше координатам.
        fadeCamera(source, true) //Чтобы не было черного экрана
        setCameraTarget(source, source) //Делаем так, чтобы камера игрока, следила за ним самим же.
        outputChatBox("Вы успешно авторизировались на сервере!", source, 0, 255, 0) //Приветственное сообщение.
    else
        outputChatBox("Введенный вами пароль неверный, или аккаунт не существует.", source, 255, 0, 0) //Если аккаунт с логином и паролем, введенным в окне авторизации отсутствует, то выводим сообщение, которое ниже.
   end
end)

Осталась последняя функция - onPlayerRegisterEx, которая наверное как Вы и догадались, срабатывает когда игрок жмет на кнопку "Зарегистрироваться"

Код:
addEvent("onPlayerRegisterEx", true)
addEventHandler("onPlayerRegisterEx", getRootElement(), function(name, password) //Функция регистрации аккаунта в базе данных.
    local result = mysql_query(database, "SELECT Name FROM players WHERE Name = '"..tostring(name).."';") //Проверяем, если ли аккаунт с именем введенным в окне регистрации.
    if(result) then //Если запрос успешный, идём дальше.
        if(mysql_num_rows(result) > 0) then //Аккаунт уже есть с таким именем.
            outputChatBox("Аккаунт с указанным вами логином уже зарегистрирован, используйте другой!", source)
        else //Аккаунта с таким именем нет, идём дальше.
            result = mysql_query(database, "INSERT INTO players (Name, Password) VALUES ('"..tostring(name).."', '"..tostring(password).."');") //Создаем аккаунт в базе данных с логином и паролем из окна регистрации.
            if(result) then //Если запрос успешный, идём дальше.
                triggerClientEvent(source, "destroyGui", source) //Вызываем клиентское событие, которое удалит окно и курсор.
                setPlayerName(source, name) //Устанавливаем игроку имя, которое он ввел в окне регистрации.
                spawnPlayer(source, 1714.96875, -1913.5341796875, 13.566567420959) //Спавним игрока на вокзале Лос - Сантоса
                setCameraTarget(source, source) //Делаем так, чтобы камера игрока, следила за ним самим же.
                fadeCamera(source, true) //Чтобы не было черного экрана
                outputChatBox("Вы успешно зарегистрировались на сервере!", source, 0, 255, 0) //Приветствуем игрока
            else
                outputChatBox("При регистрации аккаунта возникла ошибка.", source, 255, 0, 0) //Отправляем это сообщение, если аккаунт почему - то не удалось зарегистрировать.
            end
        end
    end
end)

Осталось лишь сделать обновление позиции игрока при выходе, в серверную часть добавляем:

Код:
addEventHandler ("onPlayerQuit", getRootElement(), function(quitType) //Событие происходящее при выходе игрока.
    local x, y, z = getElementPosition(source) //Получаем координаты игрока.
    mysql_query(database, "UPDATE players SET X = '"..x.."', Y = '"..y.."', Z = '"..z.."' WHERE Name = '"..getPlayerName(source).."';") //Обновляем их в базе данных.
end)

pastebin (client.lua)
pastebin (server.lua)

Автор урока: Ray_Grand

Теги: MySQL