SA-MP Forums

Go Back   SA-MP Forums > SA-MP Scripting and Plugins > Filterscripts > Includes

Reply
 
Thread Tools Display Modes
Old 04/10/2018, 08:32 PM   #1
nG Inverse
Big Clucker
 
Join Date: Feb 2012
Posts: 58
Reputation: 34
Default samp-account

samp-account



samp-account was created to allow extensive user-account systems to be streamlined by not worrying about implementation details. This means we can have a fully working user account system, with data loaded from a database, and stored to a database, all with one function call.

samp-account uses the SA:MP native SQLite database system for storage, Slice’s pointers library for data binding, ******’ YSI hooks library for callback hooking, and ******' Whirlpool plugin for password hashing.

This is a repost of sampfw > account.inc. This is now a standalone library.

Installation

Simply install to your project:

Code:
sampctl package install bwhitmire55/samp-account
Include in your code and begin using the library:

Code:
#include <account>
Functions

Code:
/*
PARAMS:  
name - The name of the database column to store the data  
type - The psuedo-type of the data (TYPE_INT, TYPE_FLOAT, TYPE_STRING)  
{Float,_}:... - The variable to store the data  
  
RETURNS:  
1 on success, otherwise 0  
*/
stock AddAccountData(const name[ACCOUNT_MAX_COLUMN_NAME], Types: type, {Float,_}:...)
Code:
/*
PARAMS:  
playerid - The playerid attempting to be registered  
password - The password of the player (in plain text)  
  
RETURNS:  
1 on success, otherwise 0  
*/
stock RegisterPlayer(playerid, const password[])
Code:
/*
PARAMS:  
playerid - The playerid attempting to be logged in  
password - The password of the player (in plain text)  
  
RETURNS:  
1 on success, otherwise 0 
*/
stock LoginPlayer(playerid, const password[])
Code:
/*
PARAMS:  
playerid - The playerid to check  
  
RETURNS:  
1 (true) if logged-in, otherwise 0 (false) 
*/
bool: IsPlayerLoggedIn(playerid)
Code:
/*
PARAMS:  
playerid - The playerid to check  
  
RETURNS:  
The unique-ID of the player in the database if exists, otherwise 0  
*/
stock GetPlayerUID(playerid)
Usage

Simply create variables in which to store your players’ data

Code:
new
    gPlayerKills[MAX_PLAYERS],
    gPlayerHealth[MAX_PLAYERS],
    gPlayerNickname[MAX_PLAYERS][MAX_PLAYER_NAME];
Add that data to the system (and database) via AddAccountData

Code:
public OnGameModeInit() {
    AddAccountData("kills", TYPE_INT, gPlayerKills);
    AddAccountData("health", TYPE_FLOAT, gPlayerHealth);
    AddAccountData("nickname", TYPE_STRING, gPlayerNickname);

    return 1;
}
Anytime a user logs into their account, their information will be loaded from the database and into the corresponding variables. Likewise for disconnecting, their data will be updated inside the database.

NOTE: The variables do no reset themselves, so you should zero-out their values upon the player exiting the server.

You are free to use the variables as normal with no effect:

Code:
public OnPlayerDeath(playerid, killerid, reason) {
    gPlayerDeaths[playerid]++;
    return 1;
}
Now we just need to call RegisterPlayer or LoginPlayer. This will most likely be done via command/dialog

Code:
ZCMD:register(playerid, params[]) {
    if(IsPlayerLoggedIn(playerid)) {
        return SendClientMessage(playerid, 0xFF0000FF, "Already logged-in!");
    }

    if(isnull(params)) {
        return SendClientMessage(playerid, 0xFFFF00FF, "Usage: /register <password>");
    }

    if(RegisterPlayer(playerid, params)) {
        SendClientMessage(playerid, 0x00FF00FF, "You have successfully registered an account!");
    } else {
        // RegisterPlayer will return 0 if the account already exists, or there is an issue with the database.
        // For this example, we'll assume the former.
        SendClientMessage(playerid, 0xFF0000FF, "Error! This username is already registered.");
    }
    return 1;
}
And that’s it! You now have a fully working account system, which can store any data you like, without touching a database or file. Nice!

Callbacks

This library also includes two callbacks, OnPlayerRegister and OnPlayerLogin.

Code:
public OnPlayerRegister(playerid) {
    SendClientMessageToAll(0x00FF00FF, "A new member has registered!");
    return 1;
}

public OnPlayerLogin(playerid) {
    SendClientMessageToAll(0x00FF00FF, "An existing member has rejoined us!");
    return 1;
}
Macros

All macros are as followed:

Code:
// The database file
#define ACCOUNT_DATABASE        "mydatabase.db"
Code:
// The database table to store the account data
#define ACCOUNT_DATABASE_TABLE  "mydatabasetable"
Code:
// The amount of 'data' you wish to store
// i.e., how many times you will use AddAccountData
#define ACCOUNT_MAX_COLUMNS     (100)
Code:
// The maximum length of a column name in the database
#define ACCOUNT_MAX_COLUMN_NAME (24)
All of these can be redefined to suite your script

Code:
#define ACCOUNT_DATABASE        "COD-DB.db"
#define ACCOUNT_DATABASE_TABLE  "users"
#include <account>
Improvements / Updates

In the future, I may extend this to optionally include predefined commands or dialogs for the user accounts. Based on reception, I may also have an option to save to a MySQL database via plugin, or files for very simple accounts.

Testing

To test, simply run the package:

Code:
sampctl package run
__________________


Last edited by nG Inverse; 04/10/2018 at 11:12 PM.
nG Inverse is offline   Reply With Quote
Old 04/10/2018, 09:27 PM   #2
Calisthenics
Gangsta
 
Join Date: May 2018
Posts: 678
Reputation: 110
Default Re: samp-account

While the concept is very good and it reminds me of an ORM system, it has two major problems.

1) SQL Injection (Always escape any input by people. There is %q placeholder in `format` function)
2) Plain text passwords (Always hash + salt passwords)
Calisthenics is offline   Reply With Quote
Old 04/10/2018, 11:11 PM   #3
nG Inverse
Big Clucker
 
Join Date: Feb 2012
Posts: 58
Reputation: 34
Default Re: samp-account

Glad you like it. I forgot to mention this uses Whirlpool internally for hashing.

Escaping was a complete oversight on my end. Will have it updated shortly!
__________________

nG Inverse is offline   Reply With Quote
Old 04/10/2018, 11:39 PM   #4
DTV
Gangsta
 
DTV's Avatar
 
Join Date: Dec 2010
Posts: 545
Reputation: 125
Default Re: samp-account

Why not use SA-MP's native hash function (SHA256_PassHash)? Makes it for one less dependency and it has salting within the function.
__________________

DTV is offline   Reply With Quote
Old 05/10/2018, 12:54 AM   #5
Variable™
Gangsta
 
Join Date: Jul 2015
Posts: 802
Reputation: 175
Default Re: samp-account

Dunno but.. I'm not sure if it's useful? And limiting it to SQLite makes it a bit unnecessary.
__________________
Discord | Website
Variable™ is offline   Reply With Quote
Old 05/10/2018, 11:35 PM   #6
DRIFT_HUNTER
High-roller
 
Join Date: Oct 2009
Posts: 2,088
Reputation: 188
Default Re: samp-account

pawn Code:
enum PlayerData {
    pAdmin,
    pHide,
    pKills,
    pDeaths
}

new pInfo[MAX_PLAYERS][PlayerData];
If i were to guess i would say that wont work, but these is why im asking (so that i know for sure and not just guess).

While these should:
pawn Code:
new pInfo[PlayerData][MAX_PLAYERS];
Right?
__________________
Looking for someone to start drifting server, drop me a pm if you are interested.


Any PM's that include question about any kind of help will be ignored.
Use appropriate boards for that
DRIFT_HUNTER is offline   Reply With Quote
Old 05/10/2018, 11:51 PM   #7
J0sh...
Banned
 
Join Date: Aug 2014
Location: Hamburger
Posts: 1,297
Reputation: 461
Default Re: samp-account

^ Uh, what?
J0sh... is offline   Reply With Quote
Old 06/10/2018, 07:55 PM   #8
Dayrion
High-roller
 
Dayrion's Avatar
 
Join Date: Jan 2016
Location: France
Posts: 1,921
Reputation: 258
Default Re: samp-account

Quote:
Originally Posted by DRIFT_HUNTER View Post
pawn Code:
enum PlayerData {
    pAdmin,
    pHide,
    pKills,
    pDeaths
}

new pInfo[MAX_PLAYERS][PlayerData];
If i were to guess i would say that wont work, but these is why im asking (so that i know for sure and not just guess).

While these should:
pawn Code:
new pInfo[PlayerData][MAX_PLAYERS];
Right?
Both are correct. The usage depends on the declaration.
In the example, you will use the variable like that: "pInfo[playerid][pAdmin]" but in your way it's: "pInfo[pAdmin][playerid]"
I admit that the first way is clearer than urs.
__________________
actor_plus - v5.0.2
« I'm a goner, somebody catch my breath,
I'm a goner, somebody catch my breath »
Dayrion is offline   Reply With Quote
Old 06/10/2018, 08:26 PM   #9
Gammix
High-roller
 
Gammix's Avatar
 
Join Date: Jan 2015
Location: Canada
Posts: 1,764
Reputation: 840
Default Re: samp-account

I really like the idea and i'd love to see some benchmarks, i know it's going to be slower than direct SQL queries but i want to see how much slower.

And if it performs out pretty well, you could implement a MySQL version of this and even take this further and create something like my EasyDB tried to achieve, but this would be way better approach!
__________________

Follow me on Github: Follow me on Spotify: Donate on Paypal:

Gammix is online now   Reply With Quote
Old 07/10/2018, 03:23 AM   #10
nG Inverse
Big Clucker
 
Join Date: Feb 2012
Posts: 58
Reputation: 34
Default Re: samp-account

This has been updated to escape values retrieved via pointer by SaveAccountData. Note that the plain text from RegisterPlayer and LoginPlayer are left alone. This is as these values are hashed via Whirlpool prior to be executed.

Quote:
Originally Posted by DRIFT_HUNTER View Post
pawn Code:
enum PlayerData {
    pAdmin,
    pHide,
    pKills,
    pDeaths
}

new pInfo[MAX_PLAYERS][PlayerData];
If i were to guess i would say that wont work, but these is why im asking (so that i know for sure and not just guess).

While these should:
pawn Code:
new pInfo[PlayerData][MAX_PLAYERS];
Right?
I haven't really tested this with enums. Most modes written now days are done so in modules which removes the need for monstrous "player enums". My guess would be the second version should work.

Quote:
Originally Posted by Gammix View Post
I really like the idea and i'd love to see some benchmarks, i know it's going to be slower than direct SQL queries but i want to see how much slower.

And if it performs out pretty well, you could implement a MySQL version of this and even take this further and create something like my EasyDB tried to achieve, but this would be way better approach!
Thanks! I highly doubt there would be a mentionable difference in speed unless pointers.inc introduces something. If you take a look at the implementation of LoadAccountData and SaveAccountData, they are both essentially just query calls. They just build the query dynamically. Wouldn't hurt to run some tests though.
__________________

nG Inverse is offline   Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
help in samp forums account Alexander1234 Everything and Nothing 3 25/08/2015 08:27 AM
Account hacking Samp Kongedet Server Support 4 11/12/2013 06:28 PM
Delete SAMP forum account? jamsterman1 General 2 17/08/2013 12:09 AM
Someone hacked my SAMP Account! xSiiiLenTx General 51 01/01/2013 10:44 PM
about SAMP account Alex89 General 9 29/11/2011 06:19 PM


All times are GMT. The time now is 04:19 AM.


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