[jTuT] MySQL R41-4 (Installation, XAMPP, Verwendung, Bedienung & Registrations-System)

    Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

    • [jTuT] MySQL R41-4 (Installation, XAMPP, Verwendung, Bedienung & Registrations-System)

      [jTuT] MySQL R41-4
      Installation, XAMPP, Verwendung, Bedienung & Registrations-System





      Hallo Zusammen,

      dieses Tutorial beschreibt die Installation sowie die Anwendung des aktuellsten MySQL Plugins für SA-MP (R41-4 / Stand 10/2017). Es baut in den Grundformen auf maddin's MySQL Tutorial auf, welches allerdings nicht mehr aktuell ist. Gerne kann dieser Thread auch für Fragen bezüglich dem Plugin oder den Codes verwendet werden.



      Inhaltsverzeichnis
      1. Voraussetzungen
      2. Kurzer Überblick
      3. Nützliches Vorwissen
      4. Aufsetzen der Datenbank in Windows mit XAMPP und phpMyAdmin
      5. SA-MP Server und MySQL Datenbank verbinden
      6. Register & Login System
      7. Hinweise und Fehlerbehebung
      8. Fußnoten
      9. Für die Faulen unter uns




      1.) Voraussetzungen
      • Einzigste Voraussetzung für dieses Tutorial ist ein vorhandener Windows PC mit dem aktuellsten SA-MP Server, beziehungsweise ein SA-MP Server mit MySQL Anbindung bei einem Hoster.




      2.) Kurzer Überblick
      • Dieses Tutorial beschreibt und erklärt die Installation, Aufsetzung und Anwendung des neusten MySQL Plugins. Außerdem wird der Aufbau der Tabelle in der Datenbank, sowie das Laden und das Speichern von Spielerstatistiken anhand von Beispielen erklärt. Am Ende haben wir ein komplett funktionsfähiges Registrations-System welches auf dem MySQL Plugin Version R41-4 basiert. Falls Du das Plugin noch nicht hast, lade es Dir bitte jetzt herunter und füge es entsprechend in Deinen Server ein.
        Es ist zu beachten, dass die Codes ganz bewusst mit englischen Variablennamen versehen worden sind, da dies der Einheitlichkeit und Allgemeinverständlichkeit eines Codes dient. Kommentare habe ich auf deutsch gehalten.




      3.) Nützliches Vorwissen
      • Was ist MySQL überhaupt?
        MySQL steht als Abkürzung für My Structured Query Language, was soviel wie "strukturierte Abfragesprache" heißt. Das ganze wird strukturiert genannt, weil es, anders als bei Dateisystemen, sehr übersichtlich aufgebaut ist, und alle Daten an einem Punkt sind, nämlich in der Datenbank. Man hat nicht tausende Dateien, die man zu verwalten hat, sondern genau eine Datenbank, in der bestmöglichst alles steht. Diese Datenbanken sind unbegrenzt* groß, es können als so viele Datensätze und Daten wie man will in der Datenbank gespeichert werden.
      • Was sind die Vorteile davon? Gibt es auch Nachteile?
        Der wohl größte Vorteil liegt in der Geschwindigkeit, in der sehr viele Daten auf einmal ausgewertet werden können. Beim abfragen von einzelnen Daten ist MySQL meist langsamer als Dateisysteme, sobald man aber viele Daten zu verwalten hat, dann lohnt sich MySQL auf jeden Fall.
        Außerdem bietet sich mit einer MySQL Datenbank die Möglichkeit, die Daten mit einer Website zu verknüpfen, das geht mit Dateien keineswegs so leicht.
        Natürlich gibt es auch Nachteile, dort ist besonders der hervorzuheben, dass es oft schwieriger für Anfänger ist, MySQL zu verstehen. Aber genau um diesem Nachteil entgegen zu wirken gibt es dieses Tutorial, damit wir gemeinsam auf die wichtigsten Dinge eingehen können, damit es anschließend ein Leichtes für Dich ist, MySQL zu verstehen.
      • Vergleich zwischen einer Datei (dini) und einer MySQL Tabelle.
        In einer Datei sieht es bekanntermaßen oft so aus:
        ->Datei: /users/Jeffry.sav

        Quellcode

        1. password=D5H)12DAI?4XST21/&DL1
        2. level=1
        3. money=1000
        4. kills=14
        5. deaths=3



        ->Datei: /users/Horst.sav

        Quellcode

        1. password=ZIJ(/5SGJ!$96T6SD§F43
        2. level=5
        3. money=99
        4. kills=19
        5. deaths=96



        Eine MySQL Tabelle sieht dann bei entsprechenden Daten so aus:


        Wie Du siehst, besteht eine MySQL Tabelle - wer hätte es gedacht - aus einer Tabelle, in der die Daten stehen. Im Beispiel der Tabelle sind dort alle Benutzer untereinander aufgeführt, es muss nicht für jeden Benutzer eine eigene Datei erstellt werden. Das hat vor allem bei Änderungen oder Server-Umzügen extreme Vorteile und erleichtert die Arbeit ungemein.
      • Externer Zugriff auf MySQL Datenbanken
        Ein externer Zugriff auf einer MySQL Datenbank (SA-MP Server auf Maschine A, MySQL Datenbank auf Maschine B) ist möglich, allerdings ist ein solches Vorgehen nicht zu empfehlen. Warum? Ganz einfach: Die Daten können während der Übertragung abgefangen werden. Natürlich sind das meist keine sensiblen Daten, aber dennoch sollte man sich darüber im Klaren sein. Außerdem, und das ist der ausschlaggebendere Punkt, dauert die Übertragung natürlich seine Zeit. Muss der MySQL Server aus den USA die Daten ins Rechenzentrum nach Frankfurt schicken, dann dauert das einen kurzen Moment (Millisekunden / Sekunden). Kommt es nun mal vor, dass der MySQL Server nicht erreichbar ist, dann hat man ein echtes Problem, denn das bedeutet, dass keine Daten mehr gelesen beziehungsweise geschrieben werden können, was oft zu Fehlern oder gar zum Server-Absturz führt.
        Daher ist es immer empfohlen, die Datenbank auf dem gleichen Server zu betreiben, auf dem auch der SA-MP Server liegt. Dies ist bei den großen Hostern ohnehin automatisch so geregelt.
      • Sammlung aller MySQL-Befehle
        Ich verweise hier auf die Sammlung aller SQL-Statements, die von MySQL unterstützt werden. In dieser Sammlung befinden sich auch Erklärungen und Beispiele zu den jeweiligen Befehlen.
        dev.mysql.com/doc/refman/5.7/en/sql-syntax.html
        Diese Liste musst Du natürlich nicht auswendig können. Es reicht zu wissen, dass diese Liste existiert, falls Du irgendwann etwas spezielles nachschauen möchtest.
        Ebenso verweise ich hier noch auf den aktuellen Wiki Eintrag für das MySQL Plugin: wiki.sa-mp.com/wiki/MySQL/R40
      • Verstehen der SQL Syntax
        Falls Du Probleme damit hast, die SQL Syntax zu verstehen, oder vor diesem Tutorial die SQL-Grundkenntnisse anhand von einfachen Beispielen lernen möchtest, empfehlen ich Dir diese Seite:
        w3schools.com/sql/default.asp
        Dort sind die wichtigsten Dinge, bis hin zu etwas komplexeren Themen, sehr gut und verständlich erklärt. Außerdem können die erklärten Funktionen direkt im Browser von Dir selbst ausprobiert werden.
        Ich kann in diesem Tutorial nicht die komplette SQL Syntax erklären, daher der Verweis auf diese wirklich gute Seite. Falls Du Fragen dazu hast, darfst Du diese natürlich trotzdem gerne hier stellen.




      4.) Aufsetzen der Datenbank in Windows mit XAMPP und phpMyAdmin
      • Installation von XAMPP
        Die Installation von XAMPP ist nur notwendig, wenn Du die MySQL Datenbank auf Deinem Windows-Rechner aufsetzen willst. Liegt der SA-MP Server bei einem Hoster, dann ist dieser Schritt nicht notwendig, da die entsprechenden Mittel in den meisten Fällen bereits gegeben sind. Sollte dies nicht der Fall sein, setze Dich einfach mit Deinem Host in Verbindung, der Support wird Dir bestimmt helfen.
        Gehen wir nun also davon aus, dass Du die MySQL Datenbank auf Deinem Rechner installieren willst. Lade hierzu XAMPP herunter. Den Download findet man auf der offiziellen Seite: Download
        Nach erfolgreichem Download findest Du in Deinem Download-Verzeichnis ein Installer-Paket um die Installation von XAMPP zu starten. Starte diesen Installer mit einem Doppelklick.


        In einigen Fällen werden Warnmeldungen wie folgende angezeigt. Diese können einfach übersprungen werden.


        Als erstes erscheint das Hauptfenster des Installers. Hier genügt es mit einem Klick auf "Next" fortzufahren.


        Im darauf folgenden Schritt kannst Du auswählen, welche Komponenten mit XAMPP auf Deinem Rechner installiert werden. Hier empfiehlt es sich, alle Komponenten auszuwählen und mit "Next" zu bestätigen.


        Jetzt musst Du den Pfad angeben, auf dem XAMPP installiert werden soll. Grundsätzlich empfiehlt es sich hier, den Standard-Pfad beizubehalten und mit "Next" zum nächsten Schritt zu springen.


        Natürlich will Dich auch dieser Installer freundlicherweise auf andere Programme aufmerksam machen. Darauf verzichtest Du empfehlenswerterweise, indem Du den Haken in der Checbox entfernst und dies mit "Next" bestätigst.


        Anschließend startet der Installer den Installationsvorgang. Hier heißt es dann: Warten und Tee trinken.


        Nach der Installation siehst Du dann den Control Panel von XAMPP. Wir benötigen hier nur die ersten beiden Teile, den Apache und MySQL.


        Klicke nun sowohl bei Apache als auch bei MySQL auf den "Start"-Button. Wenn beide Services korrekt gestartet worden sind, dann siehst Du folgendes:


        Sollte hier ein Fehler angezeigt werden, dann ist dies oftmals durch Skype verschuldet, da Skype den gleichen Port wie Apache nutzt.
        Klappe, falls Du Probleme mit dem Port hast, folgenden Spoiler auf:
      XAMPP Port ändern

      • XAMPP Port ändern
        Um den Port von Apache zu ändern musst Du einige Änderungen in den Einstellungen vornehmen. Klicke dazu bei Apache auf "Config" und wähle die httpd.conf Datei aus.


        Suche dort nach:

        Quellcode

        1. Listen 80

        und ersetze es durch:

        Quellcode

        1. Listen 8080



        Anschließend suche nach:

        Quellcode

        1. ServerName localhost:80

        und ersetze es durch:

        Quellcode

        1. ServerName localhost:8080



        Dann speichere und schließe die Datei.

        Öffne nun über den "Config"-Button die httpd-ssl.conf Datei.


        Suche dort nach:

        Quellcode

        1. Listen 443

        und ersetze es durch:

        Quellcode

        1. Listen 4433



        Anschließend suche nach:

        Quellcode

        1. <VirtualHost _default_:443>

        und ersetze es durch:

        Quellcode

        1. <VirtualHost _default_:4433>



        Dann speichere und schließe die Datei.

        Starte nun den Apache wieder. Jetzt siehst Du die neuen Ports 4433 und 8080.


        Öffne nun die Config von XAMPP.


        Und wähle dort die "Service and Port Settings" aus.


        Ändere in dem erscheinenden Fenster nun den Main Port von Apache von 80 zu 8080 und den SSL Port von 443 zu 4433. Anschließend klicke auf "Save", ebenso im Config Panel.


        Nun kannst Du den MySQL Server auch wieder starten.
        Die Änderungen wurden durchgeführt und es sollten keine Port-Probleme mehr auftreten.
        Natürlich kannst Du die Port-Nummern 8080 und 4433 auch ändern, wenn Dir diese nicht gefallen, oder diese bereits belegt sind.




      • Anlegen einer Datenbank in phpMyAdmin
        Um nun eine Datenbank anzulegen, in der die Daten gespeichert werden, müssen wir mit phpMyAdmin arbeiten. Klicke hierzu auf den "Admin"-Button von MySQL.


        Es öffnet sich nun in Deinem Standard-Browser die phpMyAdmin Startseite.


        Um jetzt eine neue Datenbank anzulegen, klicke bitte auf "Neu" am linken Randmenü.


        Gebe dort nun den gewünschten Datenbankname ein. Ich nehme für das Beispiel "samp_db". Wenn Du problemlos durch das Tutorial gehen möchtest ist es zu empfehlen, dass Du auch diesen Namen verwendest. Danach drücke bitte auf "Anlegen".


        Die Datenbank wurde nun angelegt. Um sie zu öffnen musst Du die Datenbank am linken Randmenü auswählen.


        Da in der neu erstellten Datenbank noch keine Tabelle vorhanden ist gibt uns phpMyAdmin vor eine neue Tabelle anzulegen. Wir legen uns eine Tabelle wie im obigen Beispiel an. Diese Tabelle nennen wir "users" und sie soll 7 Spalten haben.


        Anschließend siehst Du die Maske um die Spalten der Tabelle zu pflegen.
        Gebe bitte diese Daten ein:

        Quellcode

        1. id - INT (10) - Keine - Index: PRIMARY - A_I angehakt
        2. name - VARCHAR (64) - NULL
        3. password - VARCHAR (128) - NULL
        4. level - INT (3) - Wie definiert: 0
        5. money - INT (10) - Wie definiert: 0
        6. kills - INT (10) - Wie definiert: 0
        7. deaths - INT (10) - Wie definiert: 0



        Das sieht dann so aus:

        Klicke dann auf "Speichern" um die Tabelle anzulegen.

        Die fertig erstellte Tabelle "users" sieht dann in phpMyAdmin so aus:


        Nun ist die Tabelle bereit Daten aufzunehmen. Wie das geht werden wir im nächsten Kapitel behandeln.



      Optionaler Schritt: phpMyAdmin Passwort für root-Benutzer ändern (hier aufklappen falls gewünscht)

      • Optionaler Schritt: phpMyAdmin Passwort für root-Benutzer ändern
        Dieser Schritt ist optional und muss nicht zwangsläufig durchgeführt werden. Da es aus Sicherheitsgründen von phpMyAdmin vorgeschlagen wird, gehe ich auch auf diesen Punkt ein und erkläre kurz, wie man das root-Passwort ändert, da der root-Benutzer standardmäßig kein Passwort besitzt. Wenn Du diesen Schritt nicht durchführen willst, dann überspringe ihn einfach.



        Standardmäßig ist der root-Benutzer in phpMyAdmin ohne ein Passwort angelegt. Du wirst von phpMyAdmin auch darauf hingewiesen.


        Um das Passwort zu ändern, wähle oben im Menü den Reiter "Benutzer" aus.


        Dort siehst Du nun mehrere Benutzer. Du musst das Passwort von allen drei root-Benutzern ändern. Grundsätzlich sind das die gleichen Benutzer, nur mit einer anderen Schreibweise für den localhost. Das Passwort kannst Du über einen Klick auf "Rechte ändern" ändern.


        Achte bitte darauf, den root-Benutzer als letztes zu ändern, bei dem Du diese Meldung siehst:


        Klicke nun auf "Passwort ändern".


        Dort kannst Du nun das neue Passwort eingeben. Es ist zu empfehlen, dass Du allen drei root-Benutzern das gleiche Passwort gibst, damit das nicht zu Problemen führt.

        Wenn Du das neue Passwort eingegeben hast und wiederholt hast, dann bestätige die Eingabe mit "Ok" rechts unten am Bildrand.

        Sobald Du die Änderung für den root-Benutzer gemacht hast, mit dem Du gerade angemeldet bist kann sich phpMyAdmin nicht mehr anmelden, es kommt folgende Meldung:


        Schließe nun Deinen Browser beziehungsweise den Tab, in dem phpMyAdmin offen ist. Klicke im XAMPP Control Panel unter Apache auf Config und wähle dort "<Browse> [phpMyAdmin]".


        Öffne in dem Verzeichnis nun die config.inc.php Datei mit einem Texteditor.
        Suche dort die Zeile

        PHP-Quellcode

        1. $cfg['Servers'][$i]['password'] = '';


        und ersetze diese durch

        PHP-Quellcode

        1. $cfg['Servers'][$i]['password'] = 'meinPW';


        wobei Du natürlich "meinPW" mit dem von Dir vergebenen Passwort ersetzt.
        Anschließend speichere und schließe die Datei. Jetzt kannst Du phpMyAdmin wieder über einen Klick auf "Admin" bei MySQL starten. Du wirst nun wieder automatisch korrekt angemeldet.





      5.) SA-MP Server und MySQL Datenbank verbinden
      • Benötigte Dateien
        Jetzt sind wir an dem Punkt angekommen, an dem es interessant wird. Wir bauen die Verbindung zwischen dem SA-MP Server und der MySQL Datenbank auf. Hierzu benötigen wir einige Dateien. Diese kannst Du hier herunterladen: Download
        In diesem Ordner findest Du nun einige Dateien. Für die Verwendung auf einem Windows-System werden vier Dateien benötigt, diese sind: a_mysql.inc, mysql.dll, libmariadb.dll und log-core.dll. Füge nun bitte die a_mysql.inc Datei in das Verzeichnis Deines SA-MP Servers unter /pawno/includes/ ein. Die mysql.dll legst Du bitte im /plugins/ Ordner ab. Sollte sich dieser Ordner noch nicht in dem Hauptordner Deines SA-MP Servers befinden, erstelle diesen Ordner zuerst und füge die mysql.dll Datei dann dort ein. Die libmariadb.dll sowie die log-core.dll legst Du bitte in den Hauptordner Deines Servers.
        Als nächstes musst Du die server.cfg Datei öffnen, die sich im Hauptordner Deines SA-MP Servers befindet. Trage dort in der Zeile "plugins" das MySQL Plugin ein, indem Du mysql zu der Zeile hinzufügst. Sollte in der server.cfg Datei noch keine plugins-Zeile vorhanden sein, füge am Ende der Datei "plugins mysql" in einer neuen Zeile ein.


      • Verbindungsaufbau
        Um nun die Verbindung herzustellen benötigen wir einen PAWN Code. Öffne hierzu bitte die pawno.exe, die sich im Ordner /pawno/ befindet. Wähle dann entweder einen existierenden Code aus oder erstelle eine neue Datei. Es spielt herbei keine Rolle, ob der MySQL Code in einem Filterscript oder einem Gamemode aufgebaut wird, beides funktioniert ohne Probleme.
        Als erstes musst Du zu den Includes die MySQL-Include hinzufügen:

        C-Quellcode

        1. #include <a_mysql>



        Jetzt benötigen wir die Login Daten für die Datenbank. Diese hast Du ja zuvor bereits mit XAMPP und phpMyAdmin aufgesetzt. Die Login Daten sind hierfür standardmäßig der root Benutzer. Das kannst Du auch über phpMyAdmin ändern, indem Du einen neuen Benutzer anlegst, allerdings kommt es häufig zu Problemen mit den Berechtigungen, daher ist es zu empfehlen, dem root Benutzer später nur ein Passwort zu geben, das reicht, vor allem für Tests, völlig aus.
        Solltest Du die vorherigen Schritte übersprungen haben, da Du Deinen Server bei einem Hoster liegen hast, dann musst Du die Login Daten angeben, die in Deinem Control Panel des Servers angezeigt werden. Frage gegebenenfalls bei dem Support Deines Hosters nach, wenn Du nicht weißt, welche Daten das sind, beziehungsweise wo Du diese Daten findest.
        Wir geben nun also die Daten in den Code ein, dazu legen wir Konstanten an:

        C-Quellcode

        1. #define MYSQL_HOST "127.0.0.1" //IP Adresse des MySQL Servers
        2. #define MYSQL_USER "root" //Benutzername der angemeldet wird
        3. #define MYSQL_PASS "" //Passwort des Benutzers
        4. #define MYSQL_DBSE "samp_db" //Name der Datenbank



        Solltest Du andere Daten haben, nutze bitte Deine Daten. Hier nochmals der Hinweis, wenn Du zuvor das root-Passwort geändert hast, dieses Passwort zu verwenden.
        Außerdem benötigen wir noch eine Variable, die uns die Verbindungs-ID speichert. Füge direkt unter den Konstanten folgendes ein:

        C-Quellcode

        1. new MySQL:handle; //Die Connection-Handle, über die wir später auf die Tabellen der Datenbank zugreifen



        Um jetzt die Verbindung mit diesen Daten herzustellen erstellen wir uns eine kleine Funktion, die das für uns macht, vor allem auch deshalb, damit OnGameModeInit/OnFilterScriptInit nicht zu unübersichtlich wird, da dort oft ziemlich viel drin steht. Dazu musst Du bei OnGameModeInit/OnFilterScriptInit folgenden Funktionsaufruf einfügen:

        C-Quellcode

        1. MySQL_SetupConnection();



        Es besteht die Möglichkeit, zwischen den Klammern eine Zahl einzufügen, die steht dann für die Anzahl der Verbindungsversuche (TTL = Time To Lift). Standardmäßig ist das 3, wenn Du mehr oder weniger willst, trage die entsprechende Zahl dort ein, ansonsten lasse es leer.

        Ganz unten in Deinem Gamemode/Filterscript fügst Du dann diese Funktion ein:

        C-Quellcode

        1. stock MySQL_SetupConnection(ttl = 3)
        2. {
        3. print("[MySQL] Verbindungsaufbau...");
        4. //mysql_log(); //<- Kommentar vor mysql_log entfernen um den MySQL Debug-Modus zu aktivieren
        5. handle = mysql_connect(MYSQL_HOST, MYSQL_USER, MYSQL_PASS, MYSQL_DBSE);
        6. //Prüfen und gegebenenfalls wiederholen
        7. if(mysql_errno(handle) != 0)
        8. {
        9. //Fehler im Verbindungsaufbau, prüfe ob ein weiterer Versuch gestartet werden soll
        10. if(ttl > 1)
        11. {
        12. //Versuche erneut eine Verbindung aufzubauen
        13. print("[MySQL] Es konnte keine Verbindung zur Datenbank hergestellt werden.");
        14. printf("[MySQL] Starte neuen Verbindungsversuch (TTL: %d).", ttl-1);
        15. return MySQL_SetupConnection(ttl-1);
        16. }
        17. else
        18. {
        19. //Abbrechen und Server schließen
        20. print("[MySQL] Es konnte keine Verbindung zur Datenbank hergestellt werden.");
        21. print("[MySQL] Bitte prüfen Sie die Verbindungsdaten.");
        22. print("[MySQL] Der Server wird heruntergefahren.");
        23. return SendRconCommand("exit");
        24. }
        25. }
        26. printf("[MySQL] Die Verbindung zur Datenbank wurde erfolgreich hergestellt! Handle: %d", _:handle);
        27. return 1;
        28. }
        Alles anzeigen



        Mit diesem Code haben wir uns nun mehrfach abgesichert, damit auch wirklich eine Datenbankverbindung aufgebaut wird.

        Um die Verbindung zu Beenden, wenn der Gamemode/Filterscript beendet wird, füge bei OnGameModeExit/OnFilterScriptExit diese Zeile ein:

        C-Quellcode

        1. mysql_close(handle);



        Kompiliere jetzt Deinen Code und starte zum Test Deinen Server. Im besten Fall siehst Du in der Console folgende Meldung:

        Ist dies der Fall, dann kannst Du mit dem nächsten Schritt fortfahren. Sollten Probleme auftauchen, schalte den Debug-Modus an und prüfe Deine Daten. Falls Du Hilfe benötigst kannst Du gerne in diesem Thread nach Hilfe fragen, oder einen neuen Thread in der Scripting Base erstellen.



      6.) Register & Login System
      • Coding
        Da wir jetzt die Verbindung aufgebaut haben, können wir mit dem eigentlich wichtigen Teil beginnen, nämlich dem Speichersystem für die Benutzer Deines Servers, schließlich sollen deren Daten ja gespeichert werden. Hierzu benötigen wir diverse Code-Teile, die ich im folgenden Abschnitt erkläre. Wir gehen chronologisch vom Betreten des Servers bis zum Verlassen des Servers vor, und beginnen bei der Deklaration der Variablen.

        Um die Daten zur Laufzeit temporär zu speichern, ohne jedes mal auf die Datenbank zugreifen zu müssen legen wir ein Array mit den Spielerdaten an. Für eine komfortablere Bedienung nutzen wir ein Enum. Füge hierzu unter den Includes - also ganz oben in Deinem Gamemode/Filterscript - diese Deklaration ein:

        C-Quellcode

        1. enum pDataEnum
        2. {
        3. p_id,
        4. bool:pLoggedIn,
        5. pName[MAX_PLAYER_NAME],
        6. pLevel,
        7. pMoney,
        8. pKills,
        9. pDeaths
        10. }
        11. new PlayerInfo[MAX_PLAYERS][pDataEnum];
        Alles anzeigen



        Anschließend gehst Du zu OnPlayerConnect. Wenn der Spieler den Server betritt, dann soll er initialisiert werden, sprich die Variablen werden sicherheitshalter zurückgesetzt. Dazu benötigst Du diesen Code:

        C-Quellcode

        1. public OnPlayerConnect(playerid)
        2. {
        3. PlayerInfo[playerid][p_id] = 0;
        4. PlayerInfo[playerid][pLoggedIn] = false;
        5. PlayerInfo[playerid][pLevel] = 0;
        6. PlayerInfo[playerid][pMoney] = 0;
        7. PlayerInfo[playerid][pKills] = 0;
        8. PlayerInfo[playerid][pDeaths] = 0;
        9. GetPlayerName(playerid, PlayerInfo[playerid][pName], MAX_PLAYER_NAME);
        10. return 1;
        11. }
        Alles anzeigen



        Als nächstes kommt der Spieler in die Class-Selection. Hier wird OnPlayerRequestClass aufgerufen. Dort fragen wir in der Datenbank ab, ob der Spieler bereits registriert ist. Dies geht so:

        C-Quellcode

        1. public OnPlayerRequestClass(playerid)
        2. {
        3. //Wenn der Spieler die Class-Selection betritt prüfe, ob er bereits eingeloggt ist
        4. if(!PlayerInfo[playerid][pLoggedIn])
        5. {
        6. //Wenn nicht, dann prüfe ob der Spieler ein Konto hat
        7. //Dazu wird ein Query gesendet und ein neues Callback aufgerufen
        8. //%e steht für einen geprüften String (sollte anstatt %s in Queries verwendet werden)
        9. new query[128];
        10. mysql_format(handle, query, sizeof(query), "SELECT id FROM users WHERE name = '%e'", PlayerInfo[playerid][pName]);
        11. //Das Query wird abgesendet und die playerid an OnUserCheck übergeben
        12. mysql_pquery(handle, query, "OnUserCheck", "d", playerid);
        13. }
        14. return 1;
        15. }
        Alles anzeigen



        Außerdem benötigen wir nun das Callback OnUserCheck, welches Du am besten ganz unten in Deinem Gamemode/Filterscript einfügst.

        C-Quellcode

        1. forward OnUserCheck(playerid);
        2. public OnUserCheck(playerid)
        3. {
        4. //Query wurde ausgeführt und das Ergebnis im Cache gespeichert
        5. new rows;
        6. cache_get_row_count(rows);
        7. if(rows == 0)
        8. {
        9. //Der Spieler konnte nicht gefunden werden, er muss sich registrieren
        10. ShowPlayerDialog(playerid, DIALOG_REGISTER, DIALOG_STYLE_PASSWORD, "Registration", "Bitte registriere Dich:", "Ok", "Abbrechen");
        11. }
        12. else
        13. {
        14. //Es existiert ein Ergebnis, das heißt der Spieler ist registriert und muss sich einloggen
        15. ShowPlayerDialog(playerid, DIALOG_LOGIN, DIALOG_STYLE_PASSWORD, "Anmeldung", "Bitte logge Dich ein:", "Ok", "Abbrechen");
        16. }
        17. return 1;
        18. }
        Alles anzeigen



        Damit der Code ohne Fehler kompiliert, musst Du unter den Includes die beiden Dialoge definieren:

        C-Quellcode

        1. //Dialog IDs (gegebenenfalls ändern, falls bereits belegt)
        2. #define DIALOG_REGISTER 1403
        3. #define DIALOG_LOGIN 2401



        Da dem Spieler nun Dialoge angezeigt werden benötigst Du das Callback OnDialogResponse. Dort trägst Du ein, was passiert, wenn der Spieler sich registrieren oder einloggen will, je nach dem welchen Dialog der Spieler angezeigt bekommen hat.

        C-Quellcode

        1. public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[])
        2. {
        3. if(dialogid == DIALOG_REGISTER)
        4. {
        5. //Spieler hat Abbrechen gewählt
        6. if(!response) return Kick(playerid);
        7. //Wenn der Spieler kein, oder ein zu kurzes, Passwort eingegeben hat
        8. if(strlen(inputtext) < 3) return ShowPlayerDialog(playerid, DIALOG_REGISTER, DIALOG_STYLE_PASSWORD, "Registration", "Bitte registriere Dich:\n{FF0000}Mindestens 3 Zeichen!", "Ok", "Abbrechen");
        9. //Wenn alles passt wird der Spieler in der Datenbank angelegt
        10. //Als Verschlüsselung für das Passwort wird MD5 verwendet
        11. new query[256];
        12. mysql_format(handle, query, sizeof(query), "INSERT INTO users (name, password) VALUES ('%e', MD5('%e'))", PlayerInfo[playerid][pName], inputtext);
        13. //Das Query wird abgesendet und die playerid an OnUserRegister übergeben
        14. mysql_pquery(handle, query, "OnUserRegister", "d", playerid);
        15. return 1;
        16. }
        17. if(dialogid == DIALOG_LOGIN)
        18. {
        19. //Spieler hat Abbrechen gewählt
        20. if(!response) return Kick(playerid);
        21. //Wenn der Spieler kein, oder ein zu kurzes, Passwort eingegeben hat
        22. if(strlen(inputtext) < 3) return ShowPlayerDialog(playerid, DIALOG_LOGIN, DIALOG_STYLE_PASSWORD, "Anmeldung", "Bitte logge Dich ein:\n{FF0000}Mindestens 3 Zeichen!", "Ok", "Abbrechen");
        23. //Wenn alles passt wird die Datenbank ausgelesen
        24. new query[256];
        25. mysql_format(handle, query, sizeof(query), "SELECT * FROM users WHERE name = '%e' AND password = MD5('%e')", PlayerInfo[playerid][pName], inputtext);
        26. //Das Query wird abgesendet und die playerid an OnUserLogin übergeben
        27. mysql_pquery(handle, query, "OnUserLogin", "d", playerid);
        28. return 1;
        29. }
        30. return 0;
        31. }
        Alles anzeigen


        Auch hier benötigst Du die beiden neuen Callbacks, die Du wieder ganz unten in Deinem Gamemode/Filterscript einfügst:

        C-Quellcode

        1. forward OnUserRegister(playerid);
        2. public OnUserRegister(playerid)
        3. {
        4. //Der Spieler wurde in die Datenbank eingetragen, es wird die id ausgelesen
        5. PlayerInfo[playerid][p_id] = cache_insert_id();
        6. PlayerInfo[playerid][pLoggedIn] = true;
        7. SendClientMessage(playerid, 0x00FF00FF, "[Konto] Registration erfolgreich.");
        8. return 1;
        9. }


        C-Quellcode

        1. forward OnUserLogin(playerid);
        2. public OnUserLogin(playerid)
        3. {
        4. //Query wurde ausgeführt und das Ergebnis im Cache gespeichert
        5. new rows;
        6. cache_get_row_count(rows);
        7. if(rows == 0)
        8. {
        9. //Der Spieler hat ein falsches Passwort eingegeben
        10. ShowPlayerDialog(playerid, DIALOG_LOGIN, DIALOG_STYLE_PASSWORD, "Anmeldung", "Bitte logge Dich ein:\n{FF0000}Falsches Passwort!", "Ok", "Abbrechen");
        11. }
        12. else
        13. {
        14. //Es existiert ein Ergebnis, das heißt der Spieler hat das richtige Passwort eingegeben
        15. //Wir lesen nun die erste Zeile des Caches aus (ID 0)
        16. cache_get_value_name_int(0, "id", PlayerInfo[playerid][p_id]);
        17. cache_get_value_name_int(0, "level", PlayerInfo[playerid][pLevel]);
        18. cache_get_value_name_int(0, "money", PlayerInfo[playerid][pMoney]);
        19. cache_get_value_name_int(0, "kills", PlayerInfo[playerid][pKills]);
        20. cache_get_value_name_int(0, "deaths", PlayerInfo[playerid][pDeaths]);
        21. PlayerInfo[playerid][pLoggedIn] = true;
        22. SendClientMessage(playerid, 0x00FF00FF, "[Konto] Eingeloggt.");
        23. GivePlayerMoney(playerid, PlayerInfo[playerid][pMoney]);
        24. }
        25. return 1;
        26. }
        Alles anzeigen



        So, jetzt hast Du es fast geschafft. Es fehlt nur noch die Speicherung der Spielerdaten, wenn der Spieler den Server wieder verlässt.

        C-Quellcode

        1. public OnPlayerDisconnect(playerid, reason)
        2. {
        3. //Speichere den Spieler wenn er der Server verlässt
        4. SaveUserStats(playerid);
        5. return 1;
        6. }


        Für die Speicherung nutzen wir dann diese Funktion:

        C-Quellcode

        1. stock SaveUserStats(playerid)
        2. {
        3. //Wenn der Spieler nicht eingeloggt ist, dann speichere seine Statistiken nicht
        4. if(!PlayerInfo[playerid][pLoggedIn]) return 1;
        5. //Ansonsten speichere sie
        6. new query[256];
        7. mysql_format(handle, query, sizeof(query), "UPDATE users SET level = '%d', money = '%d', kills = '%d', deaths = '%d' WHERE id = '%d'",
        8. PlayerInfo[playerid][pLevel], PlayerInfo[playerid][pMoney], PlayerInfo[playerid][pKills], PlayerInfo[playerid][pDeaths], PlayerInfo[playerid][p_id]);
        9. //Das Query wird abgesendet
        10. mysql_pquery(handle, query);
        11. return 1;
        12. }
        Alles anzeigen



        Damit wären wir so gut wie durch. Um die Funktionen auch testen zu können schreiben wir noch etwas bei OnPlayerDeath rein:

        C-Quellcode

        1. public OnPlayerDeath(playerid, killerid, reason)
        2. {
        3. //Beispielcode
        4. if(killerid != INVALID_PLAYER_ID)
        5. {
        6. PlayerInfo[killerid][pKills]++;
        7. GivePlayerMoney(killerid, 10);
        8. PlayerInfo[killerid][pMoney] += 10;
        9. if(PlayerInfo[killerid][pKills] > 3)
        10. {
        11. PlayerInfo[killerid][pLevel] = 1;
        12. }
        13. }
        14. PlayerInfo[playerid][pDeaths]++;
        15. return 1;
        16. }
        Alles anzeigen



        Damit sind wir durch. Kompiliere Deinen Code und starte den Server neu.
        Der Spieler kann sich nun registrieren, einloggen und seine Statistiken werden beim Verlassen des Servers gespeichert. Die Statistiken kannst Du gegebenenfalls auch in einem Timer oder in einem Befehl speichern lassen, das bleibt Dir überlassen.

        Wenn der Spieler nun den Server betritt, dann wird ihm der Register-/Login-Dialog angezeigt.
        In der Datenbank sieht ein neuer Spieler nach der Registration so aus:


        Und nachdem er ein paar Dinge gemacht hat und den Server verlässt, sieht es so aus:

        Aktualisiere (F5), falls nötig, die Ansicht, damit die Daten korrekt angezeigt werden.


        Dieses Register-/Login-System kannst Du nun nach Belieben ausbauen, da es ja noch recht spartanisch ist. Aber Du weißt jetzt wie es geht und kannst Dich ohne Probleme durch die Materie arbeiten.





      7.) Hinweise und Fehlerbehebung
      • Der Debug Modus
        Mit dem MySQL Plugin kommt ein sehr nützlicher Debug Modus, mit dem Du alles was das Plugin macht überprüfen kannst, denn jeder Schritt wird in einem Log ausgegeben. Sollte es also einmal vorkommen, dass Du einen MySQL Code hast, der aber aus unbekannten Gründen nicht das macht, was er soll, dann kannst Du in dem MySQL Log nachschauen, was denn eigentlich passiert, oder ob möglicherweise Fehler ausgegeben werden.
        Um den MySQL Debug Modus einzuschalten musst Du nichts weiter machen, als bei OnGameModeInit/OnFilterScriptInit folgenden Funktionsaufruf hinzuzufügen:

        C-Quellcode

        1. mysql_log();

        Dies bewirkt, dass alle Aktionen des Plugins geloggt werden. Dieser Log findet sich als mysql_log.txt im Hauptverzeichnis des SA-MP Servers wieder, dort wo auch die server_log.txt liegt. Du musst Dir aber im Klaren darüber sein, dass dieser Debug Modus nicht die ganze Zeit auf dem produktiven System laufen sollte, sondern nur dann, wenn er auch benötigt wird, da durch das ganze Logging die Performance des Plugins eingeschränkt wird.
        Eine Liste zu allen Fehler-Ausgaben von MySQL findest Du hier.
      • CentOS: Failed ( libz.so.1 & libmysqlclient.so.18 )

        Unterschiede-Datei

        1. Failed (libz.so.1: cannot open shared object file: No such file or directory)
        2. Lösung : yum install zlib.i686
        3. ----------------------------------------------------
        4. Die fehlenden 32 Bit Bibliotheken für CentOS libmysqlclient.18 bei folgendem Fehler :
        5. Failed (libmysqlclient.so.18: cannot open shared object file: No such file or directory)
        6. Download : http://www.xup.in/dl,36770503/Libmysqlclient_v18.rar/
        7. Die files nach /usr/lib kopieren / einfügen !

      • Plugin wird nicht geladen
        In manchen Fällen kann es vorkommen, dass das Plugin nicht gestartet wird. Es gibt unterschiedliche Gründe dafür, diese sind häufig auf fehlende Installationen im Betriebssystem zurückzuführen. Folgende Lösungsansätze helfen in den meisten Fällen:
        • Windows: Download und Installation der All-In-One Runtimes (Download von chip.de)
        • Linux: Nutzung der mysql_static.so anstelle der mysql.so.



      8.) Fußnoten
      • * unbegrenzt
        MySQL Tabelle sind natürlich nur theoretisch unbegrenzt, alles andere wäre unrealistisch, allerdings ist es kaum möglich, dass Du die existierenden Limits erreichst. Jeder Eintrag in der Datenbank benötigt Speicher, das heißt je mehr Einträge Deine Datenbank hat, desto mehr Speicher wird benötigt. Somit sind die Grenzen vor allem durch das Betriebssystem beziehungsweise die Festplattengröße begrenzt. Genauere Informationen zu den Limits findest Du hier: dev.mysql.com/doc/refman/5.6/en/limits.html




      9.) Für die Faulen unter uns
      • Wie immer habe ich für die Faulen unter uns einen fertigen Filterscript. Im Download befindet sich zudem die Datenbank, falls jemand die importieren möchte.




      • Zusätzlich verlinke ich hier noch auf folgende Include von JustMe.77: [INCLUDE] Einzigartige Login/Register TextDraws
        In den dortigen Downloads findet sich ein fertiger Filterscript, der den Code dieses Tutorials beinhaltet.




      Änderungen:
      • 14.08.2015: Übersetzung korrigiert und Hinweis bei Debugging hinzugefügt, danke an maddin.
      • 06.09.2015: Hinweis zu CentOS Problem hinzugefügt, danke an Scene-Sector.
      • 08.11.2015: Code-Formatierung an WBB4 angepasst.
      • 19.03.2016: Spoiler-Formatierung repariert.
      • 14.09.2016: Aktualisierung des Tutorials auf R40 und Verweise auf die SQL-Syntaxliste, das Wiki sowie W3Schools in Abschnitt 3 hinzugefügt.
      • 03.10.2016: Aktualisierung des Tutorials auf R41.
      • 21.05.2017: Aktualisierung des Tutorials auf R41-2 und beheben eines Login Fehlers nach der Registration, vielen Dank an JustMe.77.
      • 02.09.2017: Aktualisierung des Tutorials auf R41-3. Verlinkung Login/Register Textdraw System, vielen Dank an JustMe.77.
      • 01.10.2017: Aktualisierung des Tutorials auf R41-4.




      Sollten während oder nach dem Tutorial Fragen oder Probleme auftauchen, dann kannst Du natürlich gerne in diesem Thread oder in der Scripting Base nachfragen.
      Viel Spaß damit! :)

      Beste Grüße,
      Jeffry 8)
      Dateien

      Dieser Beitrag wurde bereits 9 mal editiert, zuletzt von Jeffry () aus folgendem Grund: Edit 1: 14.08.2015 | Edit 2: 06.09.2015 | Edit 3: 08.11.2015 | Edit 4: 19.03.2016 | Edit 5: 14.09.2016 | Edit 6: 03.10.2016 | Edit 7: 21.05.2017 | Edit 8: 02.09.2017 | Edit 9: 01.10.2017

    • Bei mir kommt diese errors...
      Und die Dialoge werden nicht angezeigt

      [16:35:51] [DEBUG] mysql_connect - host: "127.0.0.1", user: "root", database: "samp_db", password: "****", port: 3306, autoreconnect: true, pool_size: 2
      [16:35:51] [DEBUG] CMySQLHandle::Create - creating new connection..
      [16:35:51] [DEBUG] CMySQLHandle::CMySQLHandle - constructor called
      [16:35:51] [DEBUG] CMySQLHandle::Create - connection created (id: 1)
      [16:35:51] [DEBUG] CMySQLConnection::Connect - establishing connection to database...
      [16:35:51] [DEBUG] CMySQLConnection::Connect - connection was successful
      [16:35:51] [DEBUG] CMySQLConnection::Connect - auto-reconnect has been enabled
      [16:35:51] [DEBUG] mysql_errno - connection: 1
      [16:35:51] [DEBUG] CMySQLConnection::Connect - establishing connection to database...
      [16:35:51] [DEBUG] CMySQLConnection::Connect - establishing connection to database...
      [16:35:51] [DEBUG] CMySQLConnection::Connect - establishing connection to database...
      [16:35:51] [DEBUG] CMySQLConnection::Connect - connection was successful
      [16:35:51] [DEBUG] CMySQLConnection::Connect - connection was successful
      [16:35:51] [DEBUG] CMySQLConnection::Connect - connection was successful
      [16:35:51] [DEBUG] CMySQLConnection::Connect - auto-reconnect has been enabled
      [16:35:51] [DEBUG] CMySQLConnection::Connect - auto-reconnect has been enabled
      [16:35:51] [DEBUG] CMySQLConnection::Connect - auto-reconnect has been enabled
    • Gutes Tutorial.

      Ich habe die Variante von Maddin in mein Script übernommen (stock mysql_GetInt, stock mysql_GetString usw.). :D

      Eine Frage:
      Warum ist Maddins Variante (Tutorial) "veraltet", beziehungsweise, ist diese Variante noch zu empfehlen, das mit dem Funtkionen erstellen, um die Spielerdaten zu holen?
      (Merke selber schon, dass mit Maddins Variante, der Login etwas länger dauert um die Spielerdaten zu laden, weiß nicht ob es an den Funktionen oder am MySQL Plugin (R5) liegt)
    • Danke!

      Domain_26 schrieb:

      Warum ist Maddins Variante (Tutorial) "veraltet", beziehungsweise, ist diese Variante noch zu empfehlen, das mit dem Funtkionen erstellen, um die Spielerdaten zu holen?

      Das R5 Plugin kann nicht mit mehreren Threads und Caches umgehen, das ist der Hauptgrund für den Geschwindigkeitsunterschied.

      Diese Funktionen für einfache Aufrufe sollten gemieden werden, denn wenn du 50 Stats lädst, dann werden 50 SELECT Queries gesendet, und das dauert. Das ist zwar eine einfache Variante, aber so ziemlich die schlechteste von der Performance her.
    • Hey,
      mir ist ein kleiner Fehler aufgefallen undzwar beim Speichern, speicherst die Tode als deaths aber die Spalte heißt death.
      Du hast überall diesen Fehler gemacht

      Fail, Bin wohl Müde. :dash::sleeping: :sleeping: //Edit 2: Abgesehen davon, super Tutorial!
      Mit freundlichen Grüßen,
      Chriss aka. xDesertx

      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von xDesertx ()

    • Failed (libmysqlclient.so.18: cannot open shared object file: No such file or directory)

      :D Klappt auf CentOs aber ich brauche die Libs :D

      Hab es mal so gemacht :) Da diese noch im 64 Bit Verzeichniss waren und habe diese auch ins 32 Bit kopiert!

      "ln -s /usr/lib64/libperconaserverclient.so.18 /usr/lib/libmysqlclient.so.18"
      ●▬▬▬▬▬▬▬▬▬▬▬▬▬▬ஜ۩۞۩ஜ۩۞۩ஜ۩۞۩ஜ▬▬▬▬▬▬▬▬▬▬▬▬▬●
      ♛ ▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀ ♛
      ♛ _______________________╔╦╦╦═╦╗╔═╦═╦══╦═╗_____________________ ♛
      ♛ _______________________║║║║╩╣╚╣═╣║║║║║╩╣_____________________ ♛
      ♛ _______________________╚══╩═╩═╩═╩═╩╩╩╩═╝_____________________ ♛
      ♛ ▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀ ♛
      ●▬▬▬▬▬▬▬▬▬▬▬▬▬▬ஜ۩۞۩ஜ۩۞۩ஜ۩۞۩ஜ▬▬▬▬▬▬▬▬▬▬▬▬▬●


      Immer Online solange ich Online bin : hitbox.tv/TexxhornTV

      Jetzt einen DDoS Protected SSD VPS Server kaufen : Jetzt 5% Rabatt sichern! Code : 8HX5AIER4JS8

      Nur gültig für den SSD VPS Server ...

    • Failed (libz.so.1: cannot open shared object file: No such file or directory)

      Nächster Fehler ... Ohmann !

      Fixxed :

      SA-MP Dedicated Server
      ----------------------
      v0.3.7-R2, (C)2005-2015 SA-MP Team

      [01:17:31]
      [01:17:31] Server Plugins
      [01:17:31] --------------
      [01:17:31] Loading plugin: mysql.so
      [01:17:31] >> plugin.mysql: R39-3 successfully loaded.
      [01:17:31] Loaded.
      [01:17:31] Loaded 1 plugins.
      ●▬▬▬▬▬▬▬▬▬▬▬▬▬▬ஜ۩۞۩ஜ۩۞۩ஜ۩۞۩ஜ▬▬▬▬▬▬▬▬▬▬▬▬▬●
      ♛ ▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀ ♛
      ♛ _______________________╔╦╦╦═╦╗╔═╦═╦══╦═╗_____________________ ♛
      ♛ _______________________║║║║╩╣╚╣═╣║║║║║╩╣_____________________ ♛
      ♛ _______________________╚══╩═╩═╩═╩═╩╩╩╩═╝_____________________ ♛
      ♛ ▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀ ♛
      ●▬▬▬▬▬▬▬▬▬▬▬▬▬▬ஜ۩۞۩ஜ۩۞۩ஜ۩۞۩ஜ▬▬▬▬▬▬▬▬▬▬▬▬▬●


      Immer Online solange ich Online bin : hitbox.tv/TexxhornTV

      Jetzt einen DDoS Protected SSD VPS Server kaufen : Jetzt 5% Rabatt sichern! Code : 8HX5AIER4JS8

      Nur gültig für den SSD VPS Server ...
    • Ich habe dir den kompletten Fix und die Lösung für andere per PM zukommen lassen, einfach dein Tutorial aktualisieren ! :D

      Hier eine Problemlösung für die OS Version : CentOS 7.1 , 6.X

      Sollte folgender Fehler vorhanden sein :

      Failed (libz.so.1: cannot open shared object file: No such file or directory)

      Lösung : yum install zlib.i686

      ----------------------------------------------------

      Die fehlenden 32 Bit Bibliotheken für CentOS libmysqlclient.18 bei folgendem Fehler :

      Failed (libmysqlclient.so.18: cannot open shared object file: No such file or directory)

      Download : xup.in/dl,36770503/Libmysqlclient_v18.rar/ ( Hoster löscht niemals eine Datei ! )

      Die files nach /usr/lib kopieren / einfügen !

      Damit sollte es dann keine Probleme mehr geben, bitte dann einmal in deinem Tutorial beifügen!


      Dann folgendes :

      PAWN-Quellcode

      1. stock MySQL_SetupConnection(ttl = 3)
      2. {
      3. print("[MySQL] Verbindungsaufbau...");
      4. mysql_log(LOG_ALL); //<- Kommentar vor mysql_log entfernen um den MySQL Debug-Modus zu aktivieren
      5. //Prüfen und gegebenenfalls wiederholen
      6. if(mysql_errno(handle) != 0)
      7. {
      8. //Fehler im Verbindungsaufbau, prüfe ob ein weiterer Versuch gestartet werden soll
      9. if(ttl > 1)
      10. {
      11. //Versuche erneut eine Verbindung aufzubauen
      12. print("[MySQL] Es konnte keine Verbindung zur Datenbank hergestellt werden.");
      13. printf("[MySQL] Starte neuen Verbindungsversuch (TTL: %d).", ttl-1);
      14. return MySQL_SetupConnection(ttl-1);
      15. }
      16. else
      17. {
      18. //Abbrechen und Server schließen
      19. print("[MySQL] Es konnte keine Verbindung zur Datenbank hergestellt werden.");
      20. print("[MySQL] Bitte prüfen Sie die Verbindungsdaten.");
      21. print("[MySQL] Der Server wird heruntergefahren.");
      22. return SendRconCommand("exit");
      23. }
      24. }
      25. printf("[MySQL] Die Verbindung zur Datenbank wurde erfolgreich hergestellt! Handle: %d", handle);
      26. return 1;
      27. }
      Alles anzeigen


      PAWN-Quellcode

      1. handle = mysql_connect(MYSQL_HOST, MYSQL_USER, MYSQL_DBSE, MYSQL_PASS);


      Der handler für den Datenbankaufbau kommt unter OnGameModeInit und nicht in den Stock ! Denn sonst passiert das hier :

      [02:26:40] [ERROR] mysql_pquery - invalid connection handle (id: 0)
      [02:28:41] [ERROR] mysql_close - invalid connection handle (id: 0)
      ●▬▬▬▬▬▬▬▬▬▬▬▬▬▬ஜ۩۞۩ஜ۩۞۩ஜ۩۞۩ஜ▬▬▬▬▬▬▬▬▬▬▬▬▬●
      ♛ ▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀ ♛
      ♛ _______________________╔╦╦╦═╦╗╔═╦═╦══╦═╗_____________________ ♛
      ♛ _______________________║║║║╩╣╚╣═╣║║║║║╩╣_____________________ ♛
      ♛ _______________________╚══╩═╩═╩═╩═╩╩╩╩═╝_____________________ ♛
      ♛ ▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀ ♛
      ●▬▬▬▬▬▬▬▬▬▬▬▬▬▬ஜ۩۞۩ஜ۩۞۩ஜ۩۞۩ஜ▬▬▬▬▬▬▬▬▬▬▬▬▬●


      Immer Online solange ich Online bin : hitbox.tv/TexxhornTV

      Jetzt einen DDoS Protected SSD VPS Server kaufen : Jetzt 5% Rabatt sichern! Code : 8HX5AIER4JS8

      Nur gültig für den SSD VPS Server ...

      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von Scene-Sector () aus folgendem Grund: Bugfixxes !

    • @Jeffry:

      SA-MP Dedicated Server
      ----------------------
      v0.3.7-R2, (C)2005-2015 SA-MP Team

      PAWN-Quellcode

      1. [03:07:42]
      2. [03:07:42] Server Plugins
      3. [03:07:42] --------------
      4. [03:07:42] Loading plugin: mysql
      5. [03:07:42] >> plugin.mysql: R39-3 successfully loaded.
      6. [03:07:42] Loaded.
      7. [03:07:42] Loaded 1 plugins.
      8. [03:07:42]
      9. [03:07:42] Filterscripts
      10. [03:07:42] ---------------
      11. [03:07:42] Loaded 0 filterscripts.
      12. [03:07:42] MySQL: Die Verbindung wurde erfolgreich zur Datenbank hergestellt.
      13. [03:07:42] MySQL: Die Verbindung wurde erfolgreich zur Datenbank hergestellt.
      14. [03:07:42] Number of vehicle models: 0
      Alles anzeigen


      Warum kommt das bei mir 2x ?
    • Jeffry ich habe es so gemacht wie du es auch gemacht hast und es sieht bei mir so aus:

      Code:

      PAWN-Quellcode

      1. #include <a_samp>
      2. #include<a_mysql>
      3. //defines
      4. #define MYSQL_HOST "127.0.0.1"
      5. #define MYSQL_USER "root"
      6. #define MYSQL_PASS ""
      7. #define MYSQL_DBSE "sampdeathmatch"
      8. new handle;
      9. forward OnUserCheck(playerid);
      10. forward OnUserRegister(playerid);
      11. forward OnUserLogin(playerid);
      12. enum pDataEnum
      13. {
      14. p_id,
      15. bool:pLoggedIn,
      16. pName[MAX_PLAYER_NAME],
      17. pLevel,
      18. pMoney,
      19. pKills,
      20. pTode
      21. }
      22. new PlayerInfo[MAX_PLAYERS][pDataEnum];
      23. //Dialoge:
      24. #define DIALOG_REGISTER 1
      25. #define DIALOG_LOGIN 2
      26. main()
      27. {
      28. print("\n----------------------------------");
      29. print(" Blackshadow Deathmatch");
      30. print("----------------------------------\n");
      31. }
      32. public OnGameModeInit()
      33. {
      34. MySQL_SetupConnection();
      35. SetGameModeText("Blackshadow Deathmatch");
      36. AddPlayerClass(0, 1958.3783, 1343.1572, 15.3746, 269.1425, 0, 0, 0, 0, 0, 0);
      37. return 1;
      38. }
      39. public OnGameModeExit()
      40. {
      41. mysql_close(handle);
      42. return 1;
      43. }
      44. public OnPlayerRequestClass(playerid, classid)
      45. {
      46. SetPlayerPos(playerid, 1958.3783, 1343.1572, 15.3746);
      47. SetPlayerCameraPos(playerid, 1958.3783, 1343.1572, 15.3746);
      48. SetPlayerCameraLookAt(playerid, 1958.3783, 1343.1572, 15.3746);
      49. //Wenn der Spieler die Class-Selection betritt prüfe, ob er bereits eingeloggt ist
      50. if(!PlayerInfo[playerid][pLoggedIn])
      51. {
      52. //Wenn nicht, dann prüfe ob der Spieler ein Konto hat
      53. //Dazu wird ein Query gesendet und ein neues Callback aufgerufen
      54. //%e steht für einen geprüften String (sollte anstatt %s in Queries verwendet werden)
      55. new query[128];
      56. mysql_format(handle, query, sizeof(query), "SELECT id FROM users WHERE name = '%e'", PlayerInfo[playerid][pName]);
      57. mysql_pquery(handle, query, "OnUserCheck", "d", playerid);
      58. }
      59. return 1;
      60. }
      61. public OnPlayerConnect(playerid)
      62. {
      63. PlayerInfo[playerid][p_id] = 0;
      64. PlayerInfo[playerid][pLoggedIn] = false;
      65. PlayerInfo[playerid][pLevel] = 0;
      66. PlayerInfo[playerid][pMoney] = 0;
      67. PlayerInfo[playerid][pKills] = 0;
      68. PlayerInfo[playerid][pTode] = 0;
      69. GetPlayerName(playerid,PlayerInfo[playerid][pName],MAX_PLAYER_NAME);
      70. return 1;
      71. }
      72. public OnPlayerDisconnect(playerid, reason)
      73. {
      74. SaveUserStats(playerid);
      75. return 1;
      76. }
      77. public OnPlayerSpawn(playerid)
      78. {
      79. return 1;
      80. }
      81. public OnPlayerDeath(playerid, killerid, reason)
      82. {
      83. //Beispielcode
      84. if(killerid != INVALID_PLAYER_ID)
      85. {
      86. PlayerInfo[killerid][pKills]++;
      87. GivePlayerMoney(killerid, 10);
      88. PlayerInfo[killerid][pMoney] += 10;
      89. if(PlayerInfo[killerid][pKills] > 3)
      90. {
      91. PlayerInfo[killerid][pLevel] = 1;
      92. }
      93. }
      94. PlayerInfo[playerid][pDeaths]++;
      95. return 1;
      96. }
      97. public OnVehicleSpawn(vehicleid)
      98. {
      99. return 1;
      100. }
      101. public OnVehicleDeath(vehicleid, killerid)
      102. {
      103. return 1;
      104. }
      105. public OnPlayerText(playerid, text[])
      106. {
      107. return 1;
      108. }
      109. public OnPlayerCommandText(playerid, cmdtext[])
      110. {
      111. if (strcmp("/mycommand", cmdtext, true, 10) == 0)
      112. {
      113. // Do something here
      114. return 1;
      115. }
      116. return 0;
      117. }
      118. public OnPlayerEnterVehicle(playerid, vehicleid, ispassenger)
      119. {
      120. return 1;
      121. }
      122. public OnPlayerExitVehicle(playerid, vehicleid)
      123. {
      124. return 1;
      125. }
      126. public OnPlayerStateChange(playerid, newstate, oldstate)
      127. {
      128. return 1;
      129. }
      130. public OnPlayerEnterCheckpoint(playerid)
      131. {
      132. return 1;
      133. }
      134. public OnPlayerLeaveCheckpoint(playerid)
      135. {
      136. return 1;
      137. }
      138. public OnPlayerEnterRaceCheckpoint(playerid)
      139. {
      140. return 1;
      141. }
      142. public OnPlayerLeaveRaceCheckpoint(playerid)
      143. {
      144. return 1;
      145. }
      146. public OnRconCommand(cmd[])
      147. {
      148. return 1;
      149. }
      150. public OnPlayerRequestSpawn(playerid)
      151. {
      152. return 1;
      153. }
      154. public OnObjectMoved(objectid)
      155. {
      156. return 1;
      157. }
      158. public OnPlayerObjectMoved(playerid, objectid)
      159. {
      160. return 1;
      161. }
      162. public OnPlayerPickUpPickup(playerid, pickupid)
      163. {
      164. return 1;
      165. }
      166. public OnVehicleMod(playerid, vehicleid, componentid)
      167. {
      168. return 1;
      169. }
      170. public OnVehiclePaintjob(playerid, vehicleid, paintjobid)
      171. {
      172. return 1;
      173. }
      174. public OnVehicleRespray(playerid, vehicleid, color1, color2)
      175. {
      176. return 1;
      177. }
      178. public OnPlayerSelectedMenuRow(playerid, row)
      179. {
      180. return 1;
      181. }
      182. public OnPlayerExitedMenu(playerid)
      183. {
      184. return 1;
      185. }
      186. public OnPlayerInteriorChange(playerid, newinteriorid, oldinteriorid)
      187. {
      188. return 1;
      189. }
      190. public OnPlayerKeyStateChange(playerid, newkeys, oldkeys)
      191. {
      192. return 1;
      193. }
      194. public OnRconLoginAttempt(ip[], password[], success)
      195. {
      196. return 1;
      197. }
      198. public OnPlayerUpdate(playerid)
      199. {
      200. return 1;
      201. }
      202. public OnPlayerStreamIn(playerid, forplayerid)
      203. {
      204. return 1;
      205. }
      206. public OnPlayerStreamOut(playerid, forplayerid)
      207. {
      208. return 1;
      209. }
      210. public OnVehicleStreamIn(vehicleid, forplayerid)
      211. {
      212. return 1;
      213. }
      214. public OnVehicleStreamOut(vehicleid, forplayerid)
      215. {
      216. return 1;
      217. }
      218. public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[])
      219. {
      220. if(dialogid == DIALOG_REGISTER)
      221. {
      222. //Spieler hat Abbrechen gewählt
      223. if(!response) return Kick(playerid);
      224. //Wenn der Spieler kein, oder ein zu kurzes, Passwort eingegeben hat
      225. if(strlen(inputtext) < 3) return ShowPlayerDialog(playerid, DIALOG_REGISTER, DIALOG_STYLE_PASSWORD, "Registration", "Bitte registriere Dich:\n{FF0000}Mindestens 3 Zeichen!", "Ok", "Abbrechen");
      226. //Wenn alles passt wird der Spieler in der Datenbank angelegt
      227. //Als Verschlüsselung für das Passwort wird MD5 verwendet
      228. new query[256];
      229. mysql_format(handle, query, sizeof(query), "INSERT INTO users (name, password) VALUES ('%e', MD5('%e'))", PlayerInfo[playerid][pName], inputtext);
      230. //Das Query wird abgesendet und die playerid an OnUserRegister übergeben
      231. mysql_pquery(handle, query, "OnUserRegister", "d", playerid);
      232. return 1;
      233. }
      234. if(dialogid == DIALOG_LOGIN)
      235. {
      236. //Spieler hat Abbrechen gewählt
      237. if(!response) return Kick(playerid);
      238. //Wenn der Spieler kein, oder ein zu kurzes, Passwort eingegeben hat
      239. if(strlen(inputtext) < 3) return ShowPlayerDialog(playerid, DIALOG_LOGIN, DIALOG_STYLE_PASSWORD, "Anmeldung", "Bitte logge Dich ein:\n{FF0000}Mindestens 3 Zeichen!", "Ok", "Abbrechen");
      240. //Wenn alles passt wird die Datenbank ausgelesen
      241. new query[256];
      242. mysql_format(handle, query, sizeof(query), "SELECT * FROM users WHERE name = '%e' AND password = MD5('%e')", PlayerInfo[playerid][pName], inputtext);
      243. //Das Query wird abgesendet und die playerid an OnUserLogin übergeben
      244. mysql_pquery(handle, query, "OnUserLogin", "d", playerid);
      245. return 1;
      246. }
      247. return 0;
      248. }
      249. public OnPlayerClickPlayer(playerid, clickedplayerid, source)
      250. {
      251. return 1;
      252. }
      253. stock MySQL_SetupConnection(ttl = 3)
      254. {
      255. print("[MySQL] Verbindungsaufbau...");
      256. //mysql_log(LOG_ALL); //<- Kommentar vor mysql_log entfernen um den MySQL Debug-Modus zu aktivieren
      257. handle = mysql_connect(MYSQL_HOST, MYSQL_USER, MYSQL_DBSE, MYSQL_PASS);
      258. //Prüfen und gegebenenfalls wiederholen
      259. if(mysql_errno(handle) != 0)
      260. {
      261. //Fehler im Verbindungsaufbau, prüfe ob ein weiterer Versuch gestartet werden soll
      262. if(ttl > 1)
      263. {
      264. //Versuche erneut eine Verbindung aufzubauen
      265. print("[MySQL] Es konnte keine Verbindung zur Datenbank hergestellt werden.");
      266. printf("[MySQL] Starte neuen Verbindungsversuch (TTL: %d).", ttl-1);
      267. return MySQL_SetupConnection(ttl-1);
      268. }
      269. else
      270. {
      271. //Abbrechen und Server schließen
      272. print("[MySQL] Es konnte keine Verbindung zur Datenbank hergestellt werden.");
      273. print("[MySQL] Bitte prüfen Sie die Verbindungsdaten.");
      274. print("[MySQL] Der Server wird heruntergefahren.");
      275. return SendRconCommand("exit");
      276. }
      277. }
      278. printf("[MySQL] Die Verbindung zur Datenbank wurde erfolgreich hergestellt! Handle: %d", handle);
      279. return 1;
      280. }
      281. public OnUserCheck(playerid)
      282. {
      283. //Query wurde ausgeführt und das Ergebnis im Cache gespeichert
      284. if(cache_get_row_count() == 0)
      285. {
      286. //Der Spieler konnte nicht gefunden werden, er muss sich registrieren
      287. ShowPlayerDialog(playerid, DIALOG_REGISTER, DIALOG_STYLE_PASSWORD, "Registration", "Bitte registriere Dich:", "Ok", "Abbrechen");
      288. }
      289. else
      290. {
      291. //Es existiert ein Ergebnis, das heißt der Spieler ist registriert und muss sich einloggen
      292. ShowPlayerDialog(playerid, DIALOG_LOGIN, DIALOG_STYLE_PASSWORD, "Anmeldung", "Bitte logge Dich ein:", "Ok", "Abbrechen");
      293. }
      294. return 1;
      295. }
      296. public OnUserRegister(playerid)
      297. {
      298. //Der Spieler wurde in die Datenbank eingetragen, es wird die id ausgelesen
      299. PlayerInfo[playerid][p_id] = cache_insert_id();
      300. SendClientMessage(playerid, 0x00FF00FF, "[Konto] Registration erfolgreich.");
      301. return 1;
      302. }
      303. public OnUserLogin(playerid)
      304. {
      305. //Query wurde ausgeführt und das Ergebnis im Cache gespeichert
      306. if(cache_get_row_count() == 0)
      307. {
      308. //Der Spieler hat ein falsches Passwort eingegeben
      309. ShowPlayerDialog(playerid, DIALOG_LOGIN, DIALOG_STYLE_PASSWORD, "Anmeldung", "Bitte logge Dich ein:\n{FF0000}Falsches Passwort!", "Ok", "Abbrechen");
      310. }
      311. else
      312. {
      313. //Es existiert ein Ergebnis, das heißt der Spieler hat das richtige Passwort eingegeben
      314. //Wir lesen nun die erste Zeile des Caches aus (ID 0)
      315. PlayerInfo[playerid][p_id] = cache_get_field_content_int(0, "id", handle);
      316. PlayerInfo[playerid][pLevel] = cache_get_field_content_int(0, "level", handle);
      317. PlayerInfo[playerid][pMoney] = cache_get_field_content_int(0, "money", handle);
      318. PlayerInfo[playerid][pKills] = cache_get_field_content_int(0, "kills", handle);
      319. PlayerInfo[playerid][pDeaths] = cache_get_field_content_int(0, "deaths", handle);
      320. PlayerInfo[playerid][pLoggedIn] = true;
      321. SendClientMessage(playerid, 0x00FF00FF, "[Konto] Eingeloggt.");
      322. GivePlayerMoney(playerid, PlayerInfo[playerid][pMoney]);
      323. }
      324. return 1;
      325. }
      326. stock SaveUserStats(playerid)
      327. {
      328. //Wenn der Spieler nicht eingeloggt ist, dann speichere seine Statistiken nicht
      329. if(!PlayerInfo[playerid][pLoggedIn]) return 1;
      330. //Ansonsten speichere sie
      331. new query[256];
      332. mysql_format(handle, query, sizeof(query), "UPDATE users SET level = '%d', money = '%d', kills = '%d', deaths = '%d' WHERE id = '%d'",
      333. PlayerInfo[playerid][pLevel], PlayerInfo[playerid][pMoney], PlayerInfo[playerid][pKills], PlayerInfo[playerid][pDeaths], PlayerInfo[playerid][p_id]);
      334. //Das Query wird abgesendet
      335. mysql_pquery(handle, query);
      336. return 1;
      337. }
      Alles anzeigen


      Wenn ich Compailen will kommt folgender fehler:

      Ungültige Zeile: "1103"
      Ungültige Zeile: "1367"
      Ungültige Zeile: "1381"

      Ich habe auch kein plan warum
    • Hallo
      Ich bin mit SA-MP noch nicht so vertaut. Wobei, weniger SA-MP als diese MySQL-Verbindung mein Problem ist. Aber ich denke hier bin ich richtig und Ihr könnt mir helfen.
      Das lesen der Daten aus meiner MySQL Datenbank funktioniert bereits. Aber ich brauche jetzt eine Funktion, mit der ich die Einträge in meiner Datenbank zählen kann.
      folgendes hatte ich mir gedacht:

      new query[128];
      mysql_format(dbhandle, query, sizeof(query), "SELECT COUNT(*) AS play FROM user WHERE allowed = '1' OR allowed = '0'");
      new zaehler = cache_get_field_content_int(0, "play", dbhandle);

      Das Ergebnis des SQL-Befehls gibt diese Tabelle raus, aber wie bekomme ich das Ergebnis in die Variable 'zaehler'?
      --------
      | play|
      ---------
      | 123|
      ---------