So hier die neue Version von meinem Tutorial wie ihr ein einfaches aber sicheres Login system erstellt.
Wir brauchen als ersten das INI Plugin für SAMP was hier hier findet: >>> KLICK <<<
Sobald wir das Plugin installiert haben, erstellen wir ein neuen Gamemode und includen die ini include datei mit
#include <a_samp_ini>
Als nächstes erstellen wir ein Spieler enum, das sollte so aussehen:
enum PInfo
{
pPassword[16],
pLevel,
pMoney,
Float:pX,
Float:pY,
Float:pZ,
pIsPlayerLoggedIn
}
direkt unter unserm Spieler enum erstellen wir ein array + ein globalen string array wie folgt:
new PlayerInfo[MAX_PLAYERS][PInfo];
new str[128];
als nächstes dirigieren wir zu dem "OnPlayerRequestSpawn" Callback und modifizieren es ein wenig, bis es so aussieht:
public OnPlayerRequestSpawn(playerid)
{
if(PlayerInfo[playerid][pIsPlayerLoggedIn] == 0)
{
SendClientMessage(playerid, 0xAAAAAAAA, "Du kannst nicht unangemeldet spawnen.");
return 0;
}
return 1;
}
Erklärung: if(PlayerInfo[playerid][pIsPlayerLoggedIn] == 0) Checkt ob der Spieler eingeloggt ist, ist der Spieler nicht eingeloggt Sendet er eine Chat nachricht und returnt 0, der return 0 verhindert das der Spieler spawnen kann solang die pIsPlayerLoggedIn variable 0 ist.
Und nun suchen wir das OnPlayerSpawn Callback und fügen diesen Code ein:
public OnPlayerSpawn(playerid)
{
if(PlayerInfo[playerid][pIsPlayerLoggedIn] == 0)
{
// Die ist notwendig da man dank m0d s0beit unangemeldet spawnen kann. (Fragt nicht wie es geht, ich werde es euch nicht sagen.)
format(str, sizeof(str), "%s wurde gekickt da er unangemeldet gespawn ist", GetPlayerNameEx(playerid));
SendClientMessageToAll(COLOR_LIGHT_RED, str);
return 0;
}
return 1;
}
Dieser abschnitt ist notwendig da man DANK mod so*eit ohne sich einzuloggen spawnen kann. sollte der spieler also unangemeldet spawnen, so wird er vom server gekickt.
Wir fügen nun folgenden Makro unter den Includes ein:
#define Command(%1) (!strcmp(cmdtext, %1, true, strlen(%1)) && strdel(cmdtext, 0, strlen(%1) + 1) == true)
Diesen Makro brauchen wir da er die benutzen bei OnPlayerCommandText vereinfacht, und wir gehen nun zu unseren OnPlayerCommandText callback und bearbeiten es.
public OnPlayerCommandText(playerid, cmdtext[])
{
if(Command("/login"))
{
if(PlayerInfo[playerid][pIsPlayerLoggedIn] == 1) return SendClientMessage(playerid, COLOR_LIGHT_WHITE, "Du bist schon angemeldet.");
format(str, sizeof(str), "Accounts\\%s.ini", GetPlayerNameEx(playerid));
if(!fexist(str)) return SendClientMessage(playerid, COLOR_YELLOW, "Account wurde nicht gefunden, du kannst dich nicht einloggen.");
new strPW[16];
if(sscanf(cmdtext, "s", strPW)) return SendClientMessage(playerid, COLOR_LIGHT_WHITE, "[SERVER] Benutzung: /login [Passwort]");
OnPlayerLogin(playerid, strPW);
return 1;
}
if(Command("/register"))
{
if(PlayerInfo[playerid][pIsPlayerLoggedIn] == 1) return SendClientMessage(playerid, COLOR_LIGHT_WHITE, "Du bist schon angemeldet.");
format(str, sizeof(str), "Accounts\\%s.ini", GetPlayerNameEx(playerid));
if(fexist(str)) return SendClientMessage(playerid, COLOR_YELLOW, "Account wurde gefunden, du kannst dich nicht registrieren.");
new strPW[16];
if(sscanf(cmdtext, "s", strPW)) return SendClientMessage(playerid, COLOR_LIGHT_WHITE, "[SERVER] Benutzung: /register [Passwort]");
OnPlayerRegister(playerid, strPW);
return 1;
}
return 0;
}
Die einzelnen Funktionen könnt ihr auf http://wiki.sa-mp.com sowieo http://wiki.sa-mp.de nachlesen, ich denke aber mal die dürften euch bekannt sein.
Falls ihr nicht wisst was sscanf ist: hier die erklärung: >>> Klick <<<
Wir erstellen nun ganz unten im Script ein neuen Callback namens:
public OnPlayerRegister(playerid, password[])
{
format(str, sizeof(str), "Accounts\\%s.ini", GetPlayerNameEx(playerid));
SaveString("Account", "Password", password, str);
SaveInteger("Account", "Level", random(10), str);
SaveInteger("Account", "Money", random(5000), str);
SaveFloat("Account", "PosX", 1603.928466, str);
SaveFloat("Account", "PosY", 1820.088500, str);
SaveFloat("Account", "PosZ", 10.828001, str);
SendClientMessage(playerid, COLOR_LIGHT_BLUE, "Du hast dich erfolgreich registriert, du wirst nun automatich eingeloggt.");
OnPlayerLogin(playerid, password);
return 1;
}
Dieser Callback wird aufgerufen sobald ein Spieler /register [Passwort] eingibt. Erklärungen zu den SaveFloat,Integer,String funktionen findet ihr in meinem Plugin Thread.
Wir brauchen nun noch ein Login Callback:
public OnPlayerLogin(playerid, password[])
{
format(str, sizeof(str), "Accounts\\%s.ini", GetPlayerNameEx(playerid));
LoadString("Account", "Password", "0", PlayerInfo[playerid][pPassword], str);
if(!strcmp(PlayerInfo[playerid][pPassword], password, false))
{
PlayerInfo[playerid][pLevel] = LoadInteger("Account", "Level", "0", str);
PlayerInfo[playerid][pMoney] = LoadInteger("Account", "Money", "0", str);
PlayerInfo[playerid][pX] = LoadFloat("Account", "PosX", "0.0", str);
PlayerInfo[playerid][pY] = LoadFloat("Account", "PosY", "0.0", str);
PlayerInfo[playerid][pZ] = LoadFloat("Account", "PosZ", "0.0", str);
PlayerInfo[playerid][pIsPlayerLoggedIn] = 1;
SpawnPlayer(playerid);
SetPlayerScore(playerid, PlayerInfo[playerid][pLevel));
GivePlayerMoney(playerid, PlayerInfo[playerid][pMoney]);
SetPlayerPos(playerid, PlayerInfo[playerid][pX], PlayerInfo[playerid][pY], PlayerInfo[playerid][pZ);
format(str, sizeof(str), "Willkommen zurück %s", GetPlayerNameEx(playerid));
SendClientMessage(playerid, COLOR_WHITE, str);
}else{
SendClientMessage(playerid, COLOR_LIGHT_RED, "Das Passwort war nocht korrekt.");
Kick(playerid);
}
return 1;
}
Erklärung: OnPlayerLogin lädt das Passwort als erstes aus der ini Datei, sollte das ausgelesene Passwort nicht mit dem eingegeben Passwort übereinstimmen, wird der User gekickt. sollte das Passwort doch übereinstimmen werden alle gespeicherten Daten auf den Splieler Enum zugewiesen.
Jetzt brauchen wir noch ein Callback was alles Speichert sobald der Spieler den Server verlässt:
public OnPlayerSave(playerid)
{
format(str, sizeof(str), "Accounts\\%s.ini", GetPlayerNameEx(playerid));
SaveString("Account", "Password", PlayerInfo[playerid][pPassword], str);
SaveInteger("Account", "Level", PlayerInfo[playerid][pLevel], str);
SaveInteger("Account", "Money", PlayerInfo[playerid][pMoney], str);
new Float:X, Float:Y, Float:Z
GetPlayerPos(playerid, X, Y, Z);
SaveFloat("Account", "PosX", X, str);
SaveFloat("Account", "PosY", Y, str);
SaveFloat("Account", "PosZ", Z, str);
return 1;
}
Wir dirigieren nun zu dem OnPlayerDisconnect callback und bearbeiten es:
public OnPlayerDisconnect(playerid, reason)
{
if(PlayerInfo[playerid][pIsPlayerLoggedIn] == 1)
{
OnPlayerSave(playerid);
PlayerInfo[playerid][pPassword] = 0;
PlayerInfo[playerid][pLevel] = 0;
PlayerInfo[playerid][pMoney] = 0;
PlayerInfo[playerid][pX] = 0.0;
PlayerInfo[playerid][pY] = 0.0;
PlayerInfo[playerid][pZ] = 0.0;
PlayerInfo[playerid][pIsPlayerLoggedIn] = 0;
}
return 1;
}
Erklärung: Sollte ein Spieler eingeloggt sein, so werden alle Daten aus dem Spieler Enum gespeichert sobald der Spieler den Server verlässt, dabei spielt die Art des Disconnects keine rolle.
Zur Sicherheit um Bugs zu vermeiden werden nach dem Speichern die gesammten Variablen aus dem Spieler Enum auf 0 gesetzt.
Zu guter letzt müssten wir noch unsere GetPlayerNameEx und die sscanf Funktionen erstellen:
stock GetPlayerNameEx(playerid)
{
new _NAME[MAX_PLAYER_NAME];
GetPlayerName(playerid, _NAME, sizeof(_NAME));
return _NAME;
}
Natührlich müssen wir unsere neuen 3 Callbacks auch forwarden, dazu schreiben wir folgendes einfach unter den Includes:
forward OnPlayerLogin(playerid, password[]);
forward OnPlayerRegister(playerid, password[]);
forward OnPlayerSave(playerid);
Das war es eigentlich auch schon, hoffe jetzt gibt es nicht mehr so viel zu meckern wegen meinem Tutorial.
Hier der Link zum vollen Code: >>> Klick <<<
Edit: Tutorial wurde komplett überarbeitet.
Edit: Rechtschreibung