MySQL R39-3 Register/Login System

In 10 Minuten startet der nächtliche Backupvorgang! Es kann währenddessen (ca. 10 Minuten) zu Einschränkungen bei der Nutzung des Forums kommen
Weitere Infos findet ihr im Thema Backup des Forums
Wichtiger Hinweis: Bitte ändert nicht manuell die Schriftfarbe auf schwarz sondern belasst es bei der Standardeinstellung. Somit tragt ihr dazu bei dass euer Text auch bei Verwendung unseren dunklen Forenstils noch lesbar ist!

Tipp: Ihr wollt längere Codeausschnitte oder Logfiles bereitstellen? Benutzt unseren eigenen PasteBin-Dienst Link
  • Guten Abend.


    Mein Name lautet MiX(eP).
    Ich zeig euch wie man mit MySQL R39-3 ein Register/Login System baut!
    Nun, fangen wir mal damit an.


    Was benötigen wir? :



    Ihr fügt alles in dem Script ordner Rein (Plugins, Includes.) und fügt dann auch die Namen der Plugins in die Server.cfg ein.



    Der Scripting-Part:


    Als erstes erstellen wir uns ein Static, das sollte so aussehen:


    static
    Handle,
    Name[MAX_PLAYERS][24],
    IP[MAX_PLAYERS][16]
    ;


    Dann müssen wir ja noch unsere Daten angeben. Das machen wir so:



    #define M_HOST "Host"
    #define M_USER "Benutzer"
    #define M_DATA "Datenbank"
    #define M_PASS "Passwort"


    Wie kann man nun sein Script mit der Datenbank verbinden? Dazu nutzen wir mysql_connect:
    http://wiki.sa-mp.com/wiki/MySQL/R33#mysql_connect
    Handle = mysql_connect(M_HOST, M_USER, M_DATA, M_PASS);


    So aber am besten sollte man sich 2 Sachen vergewissern, 1. Das die Verbindung steht, 2. Das der Verlauf geloggt wird.
    Um zu wissen, das die Verbindung steht müssen wir mit der Funktion mysql_errno Arbeiten.
    http://wiki.sa-mp.com/wiki/MySQL/R33#mysql_errno


    Beispiel:


    if(mysql_errno(Handle) != 0)
    {
    print("[M_CONNECTION] >> Die Verbindung zur Datenbank ist Fehlgeschlagen! << [M_CONNECTION]");
    }
    else
    {
    printf("[M_CONNECTION] >> Die Verbindung zur Datenbank %s wurde Erfolgreich Hergestellt! << [M_CONNECTION]",M_DATA);
    }


    Jetzt gucken wir mal, wie wir die Datei "mysql_log" erstellen, dazu nutzen wir mysql_log :
    http://wiki.sa-mp.com/wiki/MySQL/R33#mysql_log


    mysql_log(LOG_ERROR | LOG_WARNING | LOG_DEBUG);


    OnGamemodeInit sollte nun so aussehen:


    public OnGameModeInit()
    {
    //===[ M_Connection ]===//
    mysql_log(LOG_ERROR | LOG_WARNING | LOG_DEBUG);
    Handle = mysql_connect(M_HOST, M_USER, M_DATA, M_PASS);
    if(mysql_errno(Handle) != 0)
    {
    print("[M_CONNECTION] >> Die Verbindung zur Datenbank ist Fehlgeschlagen! << [M_CONNECTION]");
    }
    else
    {
    printf("[M_CONNECTION] >> Die Verbindung zur Datenbank %s wurde Erfolgreich Hergestellt! << [M_CONNECTION]",M_DATA);
    }
    return 1;
    }


    So nun gehen wir zu OnPlayerConnect, das haben wir nun auch, nun kommt der Richtige Scripting-Teil:
    als erstes machen wir eine Schleife die, die Spieler durchgeht. Das sieht dann so aus:


    for(new i; SpielerDaten:i < SpielerDaten; i++)
    {
    SpielerInfo[playerid][SpielerDaten:i] = 0;
    }


    Gut. nun setzen wir den Spieler auf Unregistriert, das machen wir so:


    IstRegistriert[playerid] = 0;


    Jetzt erstellen wir einen Query, der Abfragt ob ein Eintrag
    in der Datenbank existiert, vorher Fragen wir aber noch den Namen und die IP des Spielers ab. Das geht so:


    GetPlayerName(playerid, Name[playerid], 24);
    GetPlayerIp(playerid, IP[playerid], 16);


    Nun zu den Querys, erstellt eine Variable die so aussieht:


    new Query[128];


    nun Formatieren wir etwas das sieht dann so aus ( Beispiel! wird noch befüllt :(


    format(query, sizeof(query), "..", ..);


    nun der Format, wie er aussehen Sollte:


    mysql_format(Handle, Query, sizeof(Query), "SELECT * FROM `Spieler` WHERE `Spielername` = '%e' LIMIT 1", Name[playerid]);
    mysql_tquery(Handle, Query, "OnAccountCheck", "i", playerid);


    Nun das ist fertig, jetzt gehen wir zu OnPlayerDisconnect und schreiben folgendes:


    if(IstRegistriert[playerid] != 0)
    {
    SpielerSpeichern(playerid);
    }


    Nun erstellen wir unser Public "OnAccountCheck", dazu schreiben wir oben erst noch:


    forward OnAccountCheck(playerid);
    forward OnAccountLoad(playerid);
    forward OnAccountRegister(playerid);


    und:


    #define D_REGISTER 1
    #define D_LOGIN 2


    Jetzt legen wir mit OnAccountCheck los. Wir arbeiten mit cache_get_data, das soll nun so aussehen:
    http://wiki.sa-mp.com/wiki/MySQL/R33#cache_get_data


    public OnAccountCheck(playerid)
    {
    new Rows, Fields;
    cache_get_data(Rows, Fields, Handle);
    if(Rows)
    {


    Jetzt arbeiten wir weiter mit cache_get_field_content:
    http://wiki.sa-mp.com/wiki/MySQL/R33#cache_get_field_content



    new oldIP[16];
    cache_get_field_content(0, "IP", oldIP, Handle, 16);
    GetPlayerIp(playerid, oldIP, 16);
    IstRegistriert[playerid] = 1;
    if(strlen(IP[playerid]) != 0 && !strcmp(IP[playerid], oldIP, true))
    {
    OnAccountLoad(playerid);
    }
    else
    {
    cache_get_field_content(0, "Passwort", SpielerInfo[playerid][Passwort], Handle, 129);
    SpielerInfo[playerid][ID] = cache_get_field_content_int(0, "ID");
    printf("%s", SpielerInfo[playerid][Passwort]);
    ShowPlayerDialog(playerid, D_LOGIN, DIALOG_STYLE_INPUT, "Login", "Dein Account wurde gefunden. Bitte gib nun dein Passwort ein:","Einloggen","Abbrechen");
    }
    }
    else
    {
    ShowPlayerDialog(playerid, D_REGISTER, DIALOG_STYLE_INPUT, "Registrieren","Dein Account wurde nicht gefunden! Bitte gib nun dein gewünschtes Passwort ein:","Registrieren","Abbrechen");
    }
    return 1;
    }


    Nun sollte unser Public so aussehen:


    public OnAccountCheck(playerid)
    {
    new Rows, Fields;
    cache_get_data(Rows, Fields, Handle);
    if(Rows)
    {
    new oldIP[16];
    cache_get_field_content(0, "IP", oldIP, Handle, 16);
    GetPlayerIp(playerid, oldIP, 16);
    IstRegistriert[playerid] = 1;
    if(strlen(IP[playerid]) != 0 && !strcmp(IP[playerid], oldIP, true))
    {
    OnAccountLoad(playerid);
    }
    else
    {
    (!strlen(IP[playerid]) || strcmp(IP[playerid], NewIP, true));
    cache_get_field_content(0, "Passwort", SpielerInfo[playerid][Passwort], Handle, 129);
    SpielerInfo[playerid][ID] = cache_get_field_content_int(0, "ID");
    printf("%s", SpielerInfo[playerid][Passwort]);
    ShowPlayerDialog(playerid, D_LOGIN, DIALOG_STYLE_INPUT, "Login", "Dein Account wurde gefunden. Bitte gib nun dein Passwort ein:","Einloggen","Abbrechen");
    }
    }
    else
    {
    ShowPlayerDialog(playerid, D_REGISTER, DIALOG_STYLE_INPUT, "Registrieren","Dein Account wurde nicht gefunden! Bitte gib nun dein gewünschtes Passwort ein:","Registrieren","Abbrechen");
    }
    return 1;
    }


    So nun müssen wir zum dem Callback was für die Antwort, es eines Buttons von einem Dialog ist. Eine sogenannte Response.
    Das Callback nennt sich OnDialogResponse, Dazu fragen wir die jeweilige Dialog-ID ab, das erledigen wir so:


    public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[])
    {
    switch(dialogid)
    {
    case D_LOGIN:
    {
    if(!response) Kick(playerid);
    new H_Pass[129];
    new Query[100];
    WP_Hash(H_Pass, 129, inputtext);
    if(strlen(H_Pass) && !strcmp(H_Pass, SpielerInfo[playerid][Passwort]))
    {
    mysql_format(Handle, Query, sizeof(Query), "SELECT * FROM `Spieler` WHERE `Spielername` = '%e' LIMIT 1", Name[playerid]);
    mysql_tquery(Handle, Query, "OnAccountLoad", "i", playerid);
    }
    else
    {
    ShowPlayerDialog(playerid, D_LOGIN, DIALOG_STYLE_INPUT, "Login", "Dein Account wurde gefunden. Bitte gib nun dein Passwort ein\nFalsches Passwort!", "Einloggen", "Abbrechen");
    }
    }


    Nun fangen wir weiter an mit dem Dialog: D_REGISTER:


    case D_REGISTER:
    {
    if(!response) return Kick(playerid);
    if(strlen(inputtext) < 6) return ShowPlayerDialog(playerid, D_REGISTER, DIALOG_STYLE_INPUT, "Register", "Dein Account wurde nicht gefunden! Bitte gib nun dein gewünschtes Passwort ein.\nDein Passwort muss länger als 6 Zeichen sein!", "Registrieren", "Abbrechen");
    new Query[300];
    WP_Hash(SpielerInfo[playerid][Passwort], 129, inputtext);
    mysql_format(Handle, Query, sizeof(Query), "INSERT INTO `Spieler` (`Spielername`, `Passwort`, `IP`, `Admin`, `VIP`,`Morde`,`Tode`,`Level`, `Geld`) VALUES ('%e', '%s', '%s', 0, 0, 0, 0, 0, 10000)", Name[playerid], SpielerInfo[playerid][Passwort], IP[playerid]);
    mysql_tquery(Handle, Query, "OnAccountRegister", "i", playerid);
    }
    }
    return 1;
    }


    Nun sollte auch dieses Public so aussehen:


    public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[])
    {
    switch(dialogid)
    {
    case D_LOGIN:
    {
    if(!response) Kick(playerid);
    new H_Pass[129];
    new Query[100];
    WP_Hash(H_Pass, 129, inputtext);
    if(!strcmp(H_Pass, SpielerInfo[playerid][Passwort]))
    {
    mysql_format(Handle, Query, sizeof(Query), "SELECT * FROM `Spieler` WHERE `Spielername` = '%e' LIMIT 1", Name[playerid]);
    mysql_tquery(Handle, Query, "OnAccountLoad", "i", playerid);
    }
    else
    {
    ShowPlayerDialog(playerid, D_LOGIN, DIALOG_STYLE_INPUT, "Login", "Dein Account wurde gefunden. Bitte gib nun dein Passwort ein\nFalsches Passwort!", "Einloggen", "Abbrechen");
    }
    }
    case D_REGISTER:
    {
    if(!response) return Kick(playerid);
    if(strlen(inputtext) < 6) return ShowPlayerDialog(playerid, D_REGISTER, DIALOG_STYLE_INPUT, "Register", "Dein Account wurde nicht gefunden! Bitte gib nun dein gewünschtes Passwort ein.\nDein Passwort muss länger als 6 Zeichen sein!", "Registrieren", "Abbrechen");
    new Query[300];
    WP_Hash(SpielerInfo[playerid][Passwort], 129, inputtext);
    mysql_format(Handle, Query, sizeof(Query), "INSERT INTO `Spieler` (`Spielername`, `Passwort`, `IP`, `Admin`, `VIP`,`Morde`,`Tode`,`Level`, `Geld`) VALUES ('%e', '%s', '%s', 0, 0, 0, 0, 0, 50000)", Name[playerid], SpielerInfo[playerid][Passwort], IP[playerid]);
    mysql_tquery(Handle, Query, "OnAccountRegister", "i", playerid);
    }
    }
    return 1;
    }


    So, nun braucht ihr noch ein Native, und zwar dieses:


    native WP_Hash(buffer[], len, const str[]);


    Nun brauchen wir noch das Public "OnAccountLoad" und "OnAccountRegister".
    Die erstellen wir so:


    OnAccountLoad:
    public OnAccountLoad(playerid)
    {
    new Score;
    SpielerInfo[playerid][Admin] = cache_get_field_content_int(0, "Admin");
    SpielerInfo[playerid][VIP] = cache_get_field_content_int(0, "VIP");
    SpielerInfo[playerid][Geld] = cache_get_field_content_int(0, "Geld");
    SpielerInfo[playerid][Morde] = cache_get_field_content_int(0,"Morde");
    SpielerInfo[playerid][Tode] = cache_get_field_content_int(0, "Tode");
    Score = cache_get_field_content_int(0, "Level");
    SetPlayerScore(playerid, Score);
    GivePlayerMoney(playerid, SpielerInfo[playerid][Geld]);
    SendClientMessage(playerid, -1, "Du hast dich Erfolgreich Eingeloggt!");
    return 1;
    }


    OnAccountRegister:


    public OnAccountRegister(playerid)
    {
    SpielerInfo[playerid][ID] = cache_insert_id();
    printf("Neuer Account Registriert | ID: %d", SpielerInfo[playerid][ID]);
    SpielerInfo[playerid][Geld] = 10000;
    GivePlayerMoney(playerid, 10000);
    IstRegistriert[playerid] = 1;
    return 1;
    }


    Wie können wir nun den Spieler Speichern? Wir machen das per Stock! Hier ein Beispiel das funktionsfähig ist. :


    stock SpielerSpeichern(playerid)
    {
    new Query[256];
    mysql_format(Handle, Query, sizeof(Query), "UPDATE `Spieler` SET `IP`='%s', `Admin`=%d, `VIP`=%d, `Morde`=%d, `Tode`=%d, `Level`=%d, `Geld`=%d WHERE `ID`=%d",\
    IP[playerid], SpielerInfo[playerid][Admin], SpielerInfo[playerid][VIP], SpielerInfo[playerid][Morde], SpielerInfo[playerid][Tode], GetPlayerScore(playerid), SpielerInfo[playerid][Geld], SpielerInfo[playerid][ID]);
    mysql_tquery(Handle, Query, "", "");
    }


    Jetzt fehlen uns noch Folgende Sachen:


    new IstRegistriert[MAX_PLAYERS];


    enum SpielerDaten
    {
    ID,
    Passwort[129],
    Admin,
    VIP,
    Morde,
    Tode,
    Level,
    Geld
    }


    new SpielerInfo[MAX_PLAYERS][SpielerDaten];


    So das war es auch schon! Hoffe es hat euch gefallen
    Hier ist die Datenbank fürs ganze!
    Datenbank: http://www.file-upload.net/dow…10580092/Spieler.sql.html


    Hinweis! : Durch kopieren lernt ihr kein Scripten, deswegen lest es euch durch! Und versucht es mal. Scripten kann Jeder wenn er es nur Möchte!

    10 Mal editiert, zuletzt von MiX(eP) () aus folgendem Grund: Fehler Behoben, Danke Jeffry!

  • Teste dein Tutorial bitte zur Sicherheit. Ohne es zu testen habe ich schon zwei Fehler gefunden.


    1.)
    Zeile 18 in OnAccountCheck macht keinen Sinn:
    (!strlen(IP[playerid]) || strcmp(IP[playerid], NewIP, true));


    2.)
    Das Query in SpielerSpeichern ist viel zu kurz. Schon ohne die ausgefüllten Platzhalter hat es 113 Zeichen, sprich die restlichen Zeichen werden abgeschnitten, somit kommt immer ein Syntax Error.



    Und:

    Zitat

    Den R39-3 Windows Server


    Den gibt es nicht. ;)

  • Teste dein Tutorial bitte zur Sicherheit. Ohne es zu testen habe ich schon zwei Fehler gefunden.


    1.)
    Zeile 18 in OnAccountCheck macht keinen Sinn:
    (!strlen(IP[playerid]) || strcmp(IP[playerid], NewIP, true));


    2.)
    Das Query in SpielerSpeichern ist viel zu kurz. Schon ohne die ausgefüllten Platzhalter hat es 113 Zeichen, sprich die restlichen Zeichen werden abgeschnitten, somit kommt immer ein Syntax Error.


    Ich habs getestet, bisher hatte ich keine Probleme. Mhh

  • Ich habs getestet, bisher hatte ich keine Probleme. Mhh


    Hast du vielleicht noch etwas hinzugefügt zwischen dem Test und dem Posten? Teste das SpielerSpeichern mal, das sollte so nicht klappen.


    Und die angesprochene Zeile 18 sollte ein

    Zitat

    warning 215: expression has no effect


    verursachen.


    Du könntest auch noch an der Einrückung arbeiten, das sieht an manchen Stellen etwas wirr aus. Ich weiß, das macht das Forum, aber nur dann, wenn du 4 Leerzeichen und 1 Tab vermischst.
    Ansonsten macht das Tutorial einen guten Eindruck.

  • Also, ich habe es jetzt mal getestet. Interessanterweise kompiliert es sogar ohne Fehler, ihn stört diese Zeile 18 nicht, wegen dem strcmp, das ist ja eine Funktion.
    Mache sie aber trotzdem weg.
    (!strlen(IP[playerid]) || strcmp(IP[playerid], NewIP, true));



    Bei OnAccountRegister fehlt:
    IstRegistriert[playerid] = 1;


    Beim SpielerSpeichern kommt dann wie erwartet:


    Also da:
    new Query[100];
    zu:
    new Query[256];



    Außerdem lädt es die Statistiken nicht.
    Ändere bei OnPlayerConnect:
    mysql_format(Handle, Query, sizeof(Query), "SELECT `IP`, `Passwort`, `ID` FROM `Spieler` WHERE `Spielername` = '%e' LIMIT 1", Name[playerid]);
    zu:
    mysql_format(Handle, Query, sizeof(Query), "SELECT * FROM `Spieler` WHERE `Spielername` = '%e' LIMIT 1", Name[playerid]);


    Und der Timer bei OnAccountCheck muss da nicht sein. Wenn jemand innerhalb der 3 Sekunden den Server verlässt hat er alle Statistiken verloren.
    SetTimerEx("OnAccountLoad", 3000, false, "i", playerid);
    zu:
    OnAccountLoad(playerid);


    Bei OnDialogResponse solltest du zur Sicherheit noch abfragen, ob die Eingabe leer ist.
    if(!strcmp(H_Pass, SpielerInfo[playerid][Passwort])) {
    zu:
    if(strlen(H_Pass) && !strcmp(H_Pass, SpielerInfo[playerid][Passwort])) {


    Beim Login überschreibst du die IP, somit wird nicht die aktuelle IP gespeichert.
    cache_get_field_content(0, "IP", IP[playerid], Handle, 16);
    new NewIP[16];
    GetPlayerIp(playerid, NewIP, 16);
    IstRegistriert[playerid] = 1;
    if(strlen(IP[playerid]) != 0 && !strcmp(IP[playerid], NewIP, true)) {
    zu:
    new oldIP[16];
    cache_get_field_content(0, "IP", oldIP, Handle, 16);
    IstRegistriert[playerid] = 1;
    if(strlen(IP[playerid]) != 0 && !strcmp(IP[playerid], oldIP, true)) {


    Und noch ein kleiner Fehler, du schreibst beim Registrieren 50000 an Geld in die Tabelle, gibst dem Spieler aber nur 10000. Das müsstest du ändern.


    Das war es soweit, der Rest hat funktioniert.

  • Da hab ich gerad den Überblick verloren, wo steht denn da 50000?


    mysql_format(Handle, Query, sizeof(Query), "INSERT INTO `Spieler` (`Spielername`, `Passwort`, `IP`, `Admin`, `VIP`,`Morde`,`Tode`,`Level`, `Geld`) VALUES ('%e', '%s', '%s', 0, 0, 0, 0, 0, 50000)", Name[playerid], SpielerInfo[playerid][Passwort], IP[playerid]);
    Ganz am Ende.


    PS: STRG+F :klugs:

  • do.de - Domain-Offensive - Domains für alle und zu super Preisen
  • Ich habe alles genaubso nachgescriptet wie es da steht.
    Ich finde es ist ein sehr gutes Tutorial, vor allem wenn man direkt alles mit MySQL lernen will. Ich musste erstmal ein paar Errors beseitigen und auch ein paar Warnings. Hat aber alles geklappt. Mein Problem ist jetzt nur , dass wenn ich auf meinen Server connecte , zeigt er mir keine Dialoge an.


    MFG,
    [NRR]CyberFish


    /push

    Einmal editiert, zuletzt von [NRR]CyberFish () aus folgendem Grund: /push