SA-MP Forums

SA-MP Forums (http://forum.sa-mp.com/index.php)
-   Tutorials (http://forum.sa-mp.com/forumdisplay.php?f=70)
-   -   [Tutorial] Easy MySQL Register/Login system! (http://forum.sa-mp.com/showthread.php?t=160971)

WackoX 18/07/2010 01:24 PM

Easy MySQL Register/Login system! (Includes every single step!)
 
Introduction

Introduction

Over the past few years people have been using dini or ffile to create a user register/login system.
I find this very idle, slow, and difficult, and i think a lot of 'new-scripters' feel the same way as i do.

In this tutorial i will show an easy and free example of a MySQL Register/Login system, but you'll have to modify it yourself since i don't know what variables you're going to use in your gamemode.

And yes i know, i thought there was also another MySQL tutorial on the forums, but i think i can make it easyer for you guys.
If you do not agree, pick the one you like, you don't have to do it on my way.


Knowledge

Before you start doing some MySQL scripting inside your gamemode/filterscript, you'll need to have some knowledge about MySQL coding, here a few tips:

int(length) = Can be used for decimals or an integers (1337).
varchar(length) = Can be used for strings (leet), but also for floats (13.37).


Optimization

When you create a gamemode/filterscript, and certainly when based on MySQL, you need to have a good optimized script, otherwise you're gonna run out of RAM or CPU.

I recommend reading Y_Less topic first: http://forum.sa-mp.com/showthread.php?t=57018
When you don't have time for this, remember always, make the strings as short as you can!
(Example: A player name doesn't have to be 256 characters, 24 is the maximum in SA:MP)


Setting Everything Up

Plugins and Includes
Besides from just the scripting, you're gonna need some Plugins and Includes for this.
I recommend using G-sTyLeZzZ's: http://forum.sa-mp.com/showthread.php?t=56564

When you're done dowloading the right parts for your hosting, put the files in the right folders.

(Linux)
File "mysql.inc" >> Folder "Pawno/Includes"
File "mysql.so" >> Folder "Plugins" (Create if not exist)

(Windows)
File "mysql.inc" >> Folder "Pawno/Includes"
File "mysql.dll" >> Folder "Plugins" (Create if not exist)

Add this in your server.cfg:
(Linux) plugins mysql.so
(Windows) plugins mysql.dll


Creating a MySQL Database

Make sure your host has a local MySQL server running, with "PhpMyAdmin" access to it.
(Do NOT use free ones, because most of the time it doesn't work or it is way too slow!)

Go to your PhpMyAdmin site (http://YOUR_HOST_IP_HERE/PhpMyAdmin/) and login.
Now you see something like this:

http://img251.imageshack.us/img251/7513/79245630.png

Enter a new, simple, short name for your database under the text "Create new database", and press "Create".
If everything went alright you will get a notification with the text "Database NAME_HERE has been created.",
now you're inside your MySQL database and left your MySQL homepage.

Now, you want to create a new Table called "Users", now put that in, and the number of fields doesn't matter, you can always change it later,
but it has to be the same amout of variables you're gonna use (for name, password, admin level, etc).

Now, you're gonna see something like this (I've already put those fields in for example)

http://img339.imageshack.us/img339/7268/42349597.png

Like i already said in the topics "Knowledge" and "Optimization", make those 'Length/Values' as short as posible, and use the right 'Types'.
Note: All those field names (Name, Password, Admin, Money) doesn't have to be the same name as the variables inside your Gamemode,
but i recommend it since it's very useful.

When you're done press 'Save', or if you want more fields press 'Go', and leave a field blank when you don't need that one.
Now you will see something like this:

http://img291.imageshack.us/img291/7447/24820894.png

When there are players registered, you can use the button 'Browse', but since there aren't one at the moment, you can't use it.


Creating The Script

Now when you're done create the Database, we're gonna move over to your Gamemode, open that one now.

Add this include:
Code:

#include <a_mysql>
Now add this at the very beginning of your Gamemode (after all the includes).
Put in all the information you got from your host, the IP, the username to login with the password, and the name of the database you just created.
NOTE: Not the name of the Tabel (in this case: Users), but the name of the Database (in this case: Test)!!

Code:

#define MYSQL_HOST        "ip"
#define MYSQL_USER        "username"
#define MYSQL_DB        "database"
#define MYSQL_PASS        "password"

Code:

#undef MAX_PLAYERS
#define MAX_PLAYERS 50 // Put this as low as you could!

Code:

enum pEnum
{
        Name[MAX_PLAYER_NAME],
        Password[32],
        Admin,
        Money,
};
new UserStats[MAX_PLAYERS][pEnum];

new AccountExists[MAX_PLAYERS];
new PlayerLogged[MAX_PLAYERS];

Now, we're gonna put some large parts inside our gamemode, just put it somewhere it doesn't matter, but i recommend to put it all down.

Code:

ConnectMySQL()
{
        if(mysql_connect(MYSQL_HOST, MYSQL_USER, MYSQL_DB, MYSQL_PASS))
            print("[MySQL] Connection to the MySQL Database was successfully!");

        else
            print("[MySQL] Could not connect to the MySQL Database!");
}

CheckMySQL()
{
        if(mysql_ping() == -1)
                mysql_connect(MYSQL_HOST, MYSQL_USER, MYSQL_DB, MYSQL_PASS);
}

Code:

CheckAccountExists(account[])
{
        new string[128];
            format(string, sizeof(string), "SELECT * FROM Users WHERE Name = '%s'", account);
            mysql_query(string);
   
        mysql_store_result();

        new value;
        value = mysql_num_rows();
        mysql_free_result();
        return value;
}

And you're also gonna need the 'Explode' function, since the 'Split' function is mutch slower:

(Created by Westie)
Code:

explode(const sSource[], aExplode[][], const sDelimiter[] = " ", iVertices = sizeof aExplode, iLength = sizeof aExplode[]) // Created by Westie
{
        new
                iNode,
                iPointer,
                iPrevious = -1,
                iDelimiter = strlen(sDelimiter);

        while(iNode < iVertices)
        {
                iPointer = strfind(sSource, sDelimiter, false, iPointer);

                if(iPointer == -1)
                {
                        strmid(aExplode[iNode], sSource, iPrevious, strlen(sSource), iLength);
                        break;
                }
                else
                {
                        strmid(aExplode[iNode], sSource, iPrevious, iPointer, iLength);
                }

                iPrevious = (iPointer += iDelimiter);
                ++iNode;
        }
        return iPrevious;
}


Now put in the Register/Login/Save parts, you'll have to edit them to your varibles!

Code:

RegisterPlayer(playerid, password[])
{
        if(AccountExists[playerid])
                return SendClientMessage(playerid, COLOR_RED, "[ACCOUNT] You're already registered!");

        if(PlayerLogged[playerid])
                return SendClientMessage(playerid, COLOR_RED, "[ACCOUNT] You're already logged in!");

        if(strlen(password) < 3 || strlen(password) >= 32)
                return SendClientMessage(playerid, COLOR_RED, "[ACCOUNT] Your password is too short or too long!");

        CheckMySQL();

        new string[128];
        format(string, sizeof(string), "INSERT INTO Users (Name,Password) VALUES ('%s','%s')", UserStats[playerid][Name], password);
        mysql_query(string);

            AccountExists[playerid] = 1;
        SendClientMessage(playerid, COLOR_YELLOW, "[ACCOUNT] Your account has been created, please login now!");

        LoginPlayer(playerid, password);
        return 1;
}

LoginPlayer(playerid, password[])
{
        if(!AccountExists[playerid])
                return SendClientMessage(playerid, COLOR_RED, "[ACCOUNT] You're not registered!");

        if(PlayerLogged[playerid])
                    return SendClientMessage(playerid, COLOR_RED, "[ACCOUNT] You're already logged in!");

        if(strlen(password) < 3 || strlen(password) >= 32)
                    return SendClientMessage(playerid, COLOR_RED, "[ACCOUNT] Your password is too short or too long!");

        CheckMySQL();

            new string[128];
        format(string, sizeof(string), "SELECT * FROM Users WHERE Name = '%s' AND Password = '%s'", UserStats[playerid][Name], password);
        mysql_query(string);
        mysql_store_result();

        if(!mysql_num_rows())
                return SendClientMessage(playerid, COLOR_RED, "[ACCOUNT] Incorrect password!");

        new row[128]; // The length of 1 'row' total.
        new field[4][32]; // [4] = Amount of fields, [24] = Max length of the bigest field.

        mysql_fetch_row_format(row, "|");
        explode(row, field, "|");
        mysql_free_result();

        // The field starts here with 1, because the field 'Name' = 0, and we already have the name in a variable.
        format(UserStats[playerid][Password], 32, "%s", field[1]);
        UserStats[playerid][Admin] = strval(field[2]);
        UserStats[playerid][Money] = strval(field[3]);

        GivePlayerMoney(playerid, UserStats[playerid][Money]);
       
       
        format(string, sizeof(string), "[ACCOUNT] Welcome back %s, you are now logged in!", UserStats[playerid][Name]);
            SendClientMessage(playerid, COLOR_YELLOW, string);

            PlayerLogged[playerid] = 1;
            return 1;
}

SavePlayer(playerid)
{
        if(!PlayerLogged[playerid])
                return 0;

            UserStats[playerid][Money] = GetPlayerMoney(playerid);
   

        CheckMySQL();
   
            new string[256];
            format(string, sizeof(string), "UPDATE Users SET Password='%s',Admin='%d',Money='%d' WHERE Name='%s'", UserStats[playerid][Password], UserStats[playerid][Admin], UserStats[playerid][Money], UserStats[playerid][Name]);
            mysql_query(string);
            return 1;
}

Now we're gonna update your OnGameModeInit, OnPlayerConnect and OnPlayerDisconnect:

Code:

public OnGameModeInit()
{
        ConnectMySQL();
        return 1;
}

public OnPlayerConnect(playerid)
{
        GetPlayerName(playerid, UserStats[playerid][Name], MAX_PLAYER_NAME);
       
        if(CheckAccountExists(UserStats[playerid][Name])) AccountExists[playerid] = 1;
        else AccountExists[playerid] = 0;
        return 1;
}

public OnPlayerDisconnect(playerid, reason)
{
        SavePlayer(playerid);

        UserStats[playerid][Admin] = 0;
        UserStats[playerid][Money] = 0;
        return 1;
}

And now the last step, you need to implement the commands.
You can use strcmp+strtok wich is very slow and unuseful, or you can use zcmd or dcmd.

In this case we're going to use dcmd, but you can use whatever you like:

Code:

public OnPlayerCommandText(playerid, cmdtext[])
{
        dcmd(register, 8, cmdtext);
        dcmd(login, 5, cmdtext);
        return 0;
}

dcmd_register(playerid, params[])
{
        RegisterPlayer(playerid, params);
        return 1;
}

dcmd_login(playerid, params[])
{
        LoginPlayer(playerid, params);
        return 1;
}


You're done!
Congratulations with your very first own scripted MySQL based Gamemode!
Put on your server, and you'll see it will connect to the MySQL database and everything works fine!

Calgon 18/07/2010 02:08 PM

Re: Easy MySQL Register/Login system!
 
You've forgotten to add credits for the explode function, created by Westie.

WackoX 18/07/2010 03:21 PM

Re: Easy MySQL Register/Login system!
 
Quote:

Originally Posted by Calgon (Post 757443)
You've forgotten to add credits for the explode function, created by Westie.

Thank you they've been edited! do you also know how to make those screenshots smaller in the [img] code?
It stretches the forum now at my screen.

Kar 18/07/2010 04:18 PM

Re: Easy MySQL Register/Login system!
 
wow Nice imma use this in the future

Lewwy 18/07/2010 04:21 PM

Re: Easy MySQL Register/Login system!
 
No idea why but I did what you said, haven't edited a single piece from your tutorial and when I connect and register, all is well. Once I leave however, everything but my password saves, it leaves it blank. Why is this?

WackoX 18/07/2010 05:01 PM

Re: Easy MySQL Register/Login system!
 
Quote:

Originally Posted by Lewwy (Post 757575)
No idea why but I did what you said, haven't edited a single piece from your tutorial and when I connect and register, all is well. Once I leave however, everything but my password saves, it leaves it blank. Why is this?

Yes i see it now, i forgot to add the Connection part in the script :P
Please look again at the OnGameModeInit part, and put that one also in your script.

Having more problems? please post them i'd like to help you.

Lewwy 18/07/2010 05:25 PM

Re: Easy MySQL Register/Login system!
 
I had already done that, everything else loads and saves fine, except my password. It leaves the field blank after I quit or GMX.

WackoX 18/07/2010 06:36 PM

Re: Easy MySQL Register/Login system!
 
Quote:

Originally Posted by Lewwy (Post 757625)
I had already done that, everything else loads and saves fine, except my password. It leaves the field blank after I quit or GMX.

Fixed, please look at the LoginPlayer part again.
When you load in a string from MySQL, you'll need to use format or strcat.

[HiC]TheKiller 18/07/2010 08:32 PM

Re: Easy MySQL Register/Login system!
 
A few things that I suggest:

1. Instead of using a enum just use PVars for all of them.
2. Use Sscanf
3. Use dialogs
4. Please explain some of it using comments
5. Did you just copy and paste this from a script?

Lewwy 18/07/2010 08:48 PM

Re: Easy MySQL Register/Login system!
 
That line you posted in your first post doesn't work correctly for me.

Use this:
Code:

format(UserStats[playerid][Password], 32, "%s", field[1]);


All times are GMT. The time now is 11:01 PM.

Powered by vBulletin® Version 3.8.6
Copyright ©2000 - 2017, Jelsoft Enterprises Ltd.