zu
Korrekt. ![]()
EDIT:
Danke @Tommyx3 für den Hinweis mit der Handle, hatte vergessen, dass die dort komplett entfernt wurde.
zu
Korrekt. ![]()
EDIT:
Danke @Tommyx3 für den Hinweis mit der Handle, hatte vergessen, dass die dort komplett entfernt wurde.
cache_get_field_content
Entspricht jetzt
cache_get_value_name
http://wiki.sa-mp.com/wiki/MySQL/R40#cache_get_value_name
Wie soll ich die Funktion jetzt schreiben?
Das musst du mit dem neuen R40 jetzt so schreiben:
new rows;cache_get_row_count(rows);if(rows == 0)
Ich werde im Laufe der nächsten Tage das Tutorial an die R40 Version anpassen.
==================================================================================
Allerdings fehlt ein gute Erklärung zur SQL-Syntax, was bei Anfängern, die andere Systeme als Login/Register erstellen wollen, oft zu Problemen führt.
Desweiteren hätte man noch zu eine Seite verweisen können, die sämtliche SQL Befehle enthält.
Ich habe beides in Form von Verweisen zu Kapitel 3 hinzugefügt. Nochmals Danke für den Hinweis.
==================================================================================
==================================================================================
==================================================================================
Hallo Zusammen,
ich habe soeben das Tutorial auf die neuste Version (R40) angepasst.
Durch die neue Version des MySQL Plugins haben sich einige Änderungen ergeben.
Für das Upgrade von R39-3 (vorheriger Stand des Tutorials) auf R40 (aktueller Stand des Tutorials) sind folgende Anpassungen am Beispielcode notwendig (im Tutorial und Download bereits angepasst):
Der MySQL handle Variable wurde der Tag "MySQL" hinzugefügt. Dies muss bei der Deklaration angepasst werden.
new handle; //Die Connection-Handle, über die wir später auf die Tabellen der Datenbank zugreifen
zu:new MySQL:handle; //Die Connection-Handle, über die wir später auf die Tabellen der Datenbank zugreifen
Durch diverse Anpassungen wurde auch cache_get_row_count verändert. Diese gibt nun nicht mehr den Wert direkt zurück, sondern über einen Parameter. Der Code muss entsprechend angepasst werden.
if(cache_get_row_count() == 0)
zu:new rows;
cache_get_row_count(rows);
if(rows == 0)
Die gleiche Änderung hat auch cache_get_field_content_int erfahren und muss daher ebenfalls wie folgt angepasst werden.
PlayerInfo[playerid][p_id] = cache_get_field_content_int(0, "id", handle);
zu:cache_get_value_name_int(0, "id", PlayerInfo[playerid][p_id]);
Bitte beachtet, dass dies natürlich bei allen cache_get_field_content_int's gemacht werden muss, nicht nur bei der "id".
Zudem haben sich auch die anderen Cache-Funktionen in gleicher Weise geändert. Solltet Ihr also diese Funktionen ebenfalls verwenden (siehe Changelog), dann müsst Ihr diese auch anpassen.
In mysql_log wurde der Parameter entfernt und muss daher aus dem Code genommen werden.
//mysql_log(LOG_ALL); //<- Kommentar vor mysql_log entfernen um den MySQL Debug-Modus zu aktivieren
zu://mysql_log(); //<- Kommentar vor mysql_log entfernen um den MySQL Debug-Modus zu aktivieren
Jetzt die wichtigste Änderung! Hier wurde die Datenbank und das Passwort vertauscht. Auf diese Änderung macht Euch auch der Compiler nicht aufmerksam, vergesst dies also bitte nicht, sonst kann der Server keine Verbindung zur Datenbank herstellen.
handle = mysql_connect(MYSQL_HOST, MYSQL_USER, MYSQL_DBSE, MYSQL_PASS);
zu:handle = mysql_connect(MYSQL_HOST, MYSQL_USER, MYSQL_PASS, MYSQL_DBSE);
Außerdem muss in dem Informationsprint der handle noch der Tag entfernt werden, um einen Tag-Mismatch zu verhindern.
printf("[MySQL] Die Verbindung zur Datenbank wurde erfolgreich hergestellt! Handle: %d", handle);
zu:printf("[MySQL] Die Verbindung zur Datenbank wurde erfolgreich hergestellt! Handle: %d", _:handle);
Außerdem ist es nun zwingend notwendig, die aktuelle libmysql.dll sowie die neue log-core.dll Datei im Hauptordner des Servers zu haben. Ansonsten lädt der Code nicht.
Alle Änderungen findet Ihr hier:
https://github.com/pBlueG/SA-MP-MySQL/releases/tag/R40
Ich zähle daher hier nicht nochmal alle Änderungen auf. Falls Ihr Fragen zu den Änderungen habt könnt Ihr gerne wie gewohnt hier nachfragen, ebenso falls es bei der Konvertierung von R39-3 zu R40 Probleme gibt.
Bitte beachtet, dass der in diesem Post angehängte Ordner "Beispiele_R39-3" für das untenstehende alte Tutorial ist. Die neue Version findet sich im Startpost!
Viele Grüße,
Jeffry ![]()
PS:
Das Tutorial für MySQL R39-3 habe ich hier nochmal angehängt, falls es noch jemand benötigt. Ich empfehle aber die Nutzung der Version R40.
[jTuT] MySQL R39-3
Installation, XAMPP, Verwendung, Bedienung & Registrations-System
Hallo zusammen,
dieses Tutorial beschreibt die Installation sowie die Anwendung des aktuellsten MySQL Plugins für SA-MP (R39-3 / Stand 08/2015). 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
->Datei: /users/Horst.sav
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.
4.) Aufsetzen der Datenbank in Windows mit XAMPP und phpMyAdmin

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:

und ersetze es durch:
Anschließend suche nach:
und ersetze es durch:
Dann speichere und schließe die Datei.
Öffne nun über den "Config"-Button die httpd-ssl.conf Datei.
Suche dort nach:
und ersetze es durch:
Anschließend suche nach:
und ersetze es durch:
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.

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:
id - INT (10) - Keine - Index: PRIMARY - A_I angehakt
name - VARCHAR (64) - NULL
password - VARCHAR (128) - NULL
level - INT (3) - Wie definiert: 0
money - INT (10) - Wie definiert: 0
kills - INT (10) - Wie definiert: 0
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.
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
und ersetze diese durch
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
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 Hoste r 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:
#define MYSQL_HOST "127.0.0.1" //IP Adresse des MySQL Servers
#define MYSQL_USER "root" //Benutzername der angemeldet wird
#define MYSQL_PASS "" //Passwort des Benutzers
#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:
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:
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:
stock MySQL_SetupConnection(ttl = 3)
{
print("[MySQL] Verbindungsaufbau...");
//mysql_log(LOG_ALL); //<- Kommentar vor mysql_log entfernen um den MySQL Debug-Modus zu aktivieren
handle = mysql_connect(MYSQL_HOST, MYSQL_USER, MYSQL_DBSE, MYSQL_PASS);
//Prüfen und gegebenenfalls wiederholen
if(mysql_errno(handle) != 0)
{
//Fehler im Verbindungsaufbau, prüfe ob ein weiterer Versuch gestartet werden soll
if(ttl > 1)
{
//Versuche erneut eine Verbindung aufzubauen
print("[MySQL] Es konnte keine Verbindung zur Datenbank hergestellt werden.");
printf("[MySQL] Starte neuen Verbindungsversuch (TTL: %d).", ttl-1);
return MySQL_SetupConnection(ttl-1);
}
else
{
//Abbrechen und Server schließen
print("[MySQL] Es konnte keine Verbindung zur Datenbank hergestellt werden.");
print("[MySQL] Bitte prüfen Sie die Verbindungsdaten.");
print("[MySQL] Der Server wird heruntergefahren.");
return SendRconCommand("exit");
}
}
printf("[MySQL] Die Verbindung zur Datenbank wurde erfolgreich hergestellt! Handle: %d", handle);
return 1;
}
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:
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
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:
enum pDataEnum
{
p_id,
bool:pLoggedIn,
pName[MAX_PLAYER_NAME],
pLevel,
pMoney,
pKills,
pDeaths
}
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:
public OnPlayerConnect(playerid)
{
PlayerInfo[playerid][p_id] = 0;
PlayerInfo[playerid][pLoggedIn] = false;
PlayerInfo[playerid][pLevel] = 0;
PlayerInfo[playerid][pMoney] = 0;
PlayerInfo[playerid][pKills] = 0;
PlayerInfo[playerid][pDeaths] = 0;
GetPlayerName(playerid, PlayerInfo[playerid][pName], MAX_PLAYER_NAME);
return 1;
}
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:
public OnPlayerRequestClass(playerid)
{
//Wenn der Spieler die Class-Selection betritt prüfe, ob er bereits eingeloggt ist
if(!PlayerInfo[playerid][pLoggedIn])
{
//Wenn nicht, dann prüfe ob der Spieler ein Konto hat
//Dazu wird ein Query gesendet und ein neues Callback aufgerufen
//%e steht für einen geprüften String (sollte anstatt %s in Queries verwendet werden)
new query[128];
mysql_format(handle, query, sizeof(query), "SELECT id FROM users WHERE name = '%e'", PlayerInfo[playerid][pName]);
//Das Query wird abgesendet und die playerid an OnUserCheck übergeben
mysql_pquery(handle, query, "OnUserCheck", "d", playerid);
}
return 1;
}
Alles anzeigen
Außerdem benötigen wir nun das Callback OnUserCheck, welches Du am besten ganz unten in Deinem Gamemode/Filterscript einfügst.
forward OnUserCheck(playerid);
public OnUserCheck(playerid)
{
//Query wurde ausgeführt und das Ergebnis im Cache gespeichert
if(cache_get_row_count() == 0)
{
//Der Spieler konnte nicht gefunden werden, er muss sich registrieren
ShowPlayerDialog(playerid, DIALOG_REGISTER, DIALOG_STYLE_PASSWORD, "Registration", "Bitte registriere Dich:", "Ok", "Abbrechen");
}
else
{
//Es existiert ein Ergebnis, das heißt der Spieler ist registriert und muss sich einloggen
ShowPlayerDialog(playerid, DIALOG_LOGIN, DIALOG_STYLE_PASSWORD, "Anmeldung", "Bitte logge Dich ein:", "Ok", "Abbrechen");
}
return 1;
}
Alles anzeigen
Damit der Code ohne Fehler kompiliert, musst Du unter den Includes die beiden Dialoge definieren:
//Dialog IDs (gegebenenfalls ändern, falls bereits belegt)
#define DIALOG_REGISTER 1403
#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.
public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[])
{
if(dialogid == DIALOG_REGISTER)
{
//Spieler hat Abbrechen gewählt
if(!response) return Kick(playerid);
//Wenn der Spieler kein, oder ein zu kurzes, Passwort eingegeben hat
if(strlen(inputtext) < 3) return ShowPlayerDialog(playerid, DIALOG_REGISTER, DIALOG_STYLE_PASSWORD, "Registration", "Bitte registriere Dich:\n{FF0000}Mindestens 3 Zeichen!", "Ok", "Abbrechen");
//Wenn alles passt wird der Spieler in der Datenbank angelegt
//Als Verschlüsselung für das Passwort wird MD5 verwendet
new query[256];
mysql_format(handle, query, sizeof(query), "INSERT INTO users (name, password) VALUES ('%e', MD5('%e'))", PlayerInfo[playerid][pName], inputtext);
//Das Query wird abgesendet und die playerid an OnUserRegister übergeben
mysql_pquery(handle, query, "OnUserRegister", "d", playerid);
return 1;
}
if(dialogid == DIALOG_LOGIN)
{
//Spieler hat Abbrechen gewählt
if(!response) return Kick(playerid);
//Wenn der Spieler kein, oder ein zu kurzes, Passwort eingegeben hat
if(strlen(inputtext) < 3) return ShowPlayerDialog(playerid, DIALOG_LOGIN, DIALOG_STYLE_PASSWORD, "Anmeldung", "Bitte logge Dich ein:\n{FF0000}Mindestens 3 Zeichen!", "Ok", "Abbrechen");
//Wenn alles passt wird die Datenbank ausgelesen
new query[256];
mysql_format(handle, query, sizeof(query), "SELECT * FROM users WHERE name = '%e' AND password = MD5('%e')", PlayerInfo[playerid][pName], inputtext);
//Das Query wird abgesendet und die playerid an OnUserLogin übergeben
mysql_pquery(handle, query, "OnUserLogin", "d", playerid);
return 1;
}
return 0;
}
Alles anzeigen
Auch hier benötigst Du die beiden neuen Callbacks, die Du wieder ganz unten in Deinem Gamemode/Filterscript einfügst:
forward OnUserRegister(playerid);
public OnUserRegister(playerid)
{
//Der Spieler wurde in die Datenbank eingetragen, es wird die id ausgelesen
PlayerInfo[playerid][p_id] = cache_insert_id();
SendClientMessage(playerid, 0x00FF00FF, "[Konto] Registration erfolgreich.");
return 1;
}
forward OnUserLogin(playerid);
public OnUserLogin(playerid)
{
//Query wurde ausgeführt und das Ergebnis im Cache gespeichert
if(cache_get_row_count() == 0)
{
//Der Spieler hat ein falsches Passwort eingegeben
ShowPlayerDialog(playerid, DIALOG_LOGIN, DIALOG_STYLE_PASSWORD, "Anmeldung", "Bitte logge Dich ein:\n{FF0000}Falsches Passwort!", "Ok", "Abbrechen");
}
else
{
//Es existiert ein Ergebnis, das heißt der Spieler hat das richtige Passwort eingegeben
//Wir lesen nun die erste Zeile des Caches aus (ID 0)
PlayerInfo[playerid][p_id] = cache_get_field_content_int(0, "id", handle);
PlayerInfo[playerid][pLevel] = cache_get_field_content_int(0, "level", handle);
PlayerInfo[playerid][pMoney] = cache_get_field_content_int(0, "money", handle);
PlayerInfo[playerid][pKills] = cache_get_field_content_int(0, "kills", handle);
PlayerInfo[playerid][pDeaths] = cache_get_field_content_int(0, "deaths", handle);
PlayerInfo[playerid][pLoggedIn] = true;
SendClientMessage(playerid, 0x00FF00FF, "[Konto] Eingeloggt.");
GivePlayerMoney(playerid, PlayerInfo[playerid][pMoney]);
}
return 1;
}
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.
public OnPlayerDisconnect(playerid, reason)
{
//Speichere den Spieler wenn er der Server verlässt
SaveUserStats(playerid);
return 1;
}
Für die Speicherung nutzen wir dann diese Funktion:
stock SaveUserStats(playerid)
{
//Wenn der Spieler nicht eingeloggt ist, dann speichere seine Statistiken nicht
if(!PlayerInfo[playerid][pLoggedIn]) return 1;
//Ansonsten speichere sie
new query[256];
mysql_format(handle, query, sizeof(query), "UPDATE users SET level = '%d', money = '%d', kills = '%d', deaths = '%d' WHERE id = '%d'",
PlayerInfo[playerid][pLevel], PlayerInfo[playerid][pMoney], PlayerInfo[playerid][pKills], PlayerInfo[playerid][pDeaths], PlayerInfo[playerid][p_id]);
//Das Query wird abgesendet
mysql_pquery(handle, query);
return 1;
}
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:
public OnPlayerDeath(playerid, killerid, reason)
{
//Beispielcode
if(killerid != INVALID_PLAYER_ID)
{
PlayerInfo[killerid][pKills]++;
GivePlayerMoney(killerid, 10);
PlayerInfo[killerid][pMoney] += 10;
if(PlayerInfo[killerid][pKills] > 3)
{
PlayerInfo[killerid][pLevel] = 1;
}
}
PlayerInfo[playerid][pDeaths]++;
return 1;
}
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
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.
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 : http://www.xup.in/dl,36770503/Libmysqlclient_v18.rar/
Die files nach /usr/lib kopieren / einfügen !
Alles anzeigen
8.) Fußnoten
9.) Für die Faulen unter uns

Änderungen:
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 ![]()
Dann scheinen in der Tabelle JobVehicles bereits alle IDs zu existieren. Prüfe das bitte mal und leere die Tabelle eventuell.
Was funktioniert denn nicht?
Wird dir irgendwas im Server Log oder im Chat ausgegeben, wenn du den Befehl eingibst? Kommen die Nachrichten?
Zum einen darf die Schleife nur durch die Anzahl der Zeilen gehen, anstatt durch die gesamte Array-Größe und zum anderen musst du überall die Cache-Zeile "i" anstatt "0" auslesen.
forward LoadCars(playerid);
public LoadCars(playerid)
{
new rows = cache_get_row_count();
if(rows == 0) return 1;
printf("1");
for(new i = 0; i < rows; i++)
{
if(cInfo[i][c_vID] != 0) continue;
cache_get_field_content(i, "c_besitzer", cInfo[i][c_besitzer], dbhandle, 32);
cInfo[i][c_model] = cache_get_field_content_int(i, "c_model", dbhandle);
cInfo[i][c_x] = cache_get_field_content_float(i, "c_x", dbhandle);
cInfo[i][c_y] = cache_get_field_content_float(i, "c_y", dbhandle);
cInfo[i][c_z] = cache_get_field_content_float(i, "c_z", dbhandle);
cInfo[i][c_r] = cache_get_field_content_float(i, "c_r", dbhandle);
cInfo[i][c_color1] = cache_get_field_content_int(i, "c_color1", dbhandle);
cInfo[i][c_color2] = cache_get_field_content_int(i, "c_color2", dbhandle);
cInfo[i][c_vID] = CreateVehicle(cInfo[i][c_model],cInfo[i][c_x],cInfo[i][c_y],cInfo[i][c_z],cInfo[i][c_r],cInfo[i][c_color1],cInfo[i][c_color2],0);
}
return 1;
}
if(cache_get_row_count() == 0)
zu:
if(cache_get_row_count() >= 3)
Beachte, dass dies so aber nicht klappen wird. Wenn du mysql_pquery nutzt, musst du die Cache Abfrage in einem Callback (neues public) machen.
Ansonsten ändere
mysql_pquery(dbhandle, query);
zu:
mysql_query(dbhandle, query);
Dies hebelt allerdings den Performancegewinn der neuen Plugins aus und sollte daher nur bedingt genutzt werden.
Wenn du die Tabellenstruktur der MySQL Tabelle meinst:
Man kann zwar die Felder auslesen lassen, die sich in den Queries befinden, es wird allerdings schwer, die genauen Datentypen der Felder zu erkennen. Außerdem ist es bei SQL Statements wie SELECT * nicht wirklich erkennbar, was ausgelesen werden soll.
Von daher kann man zwar schon was auslesen mit einem entsprechenden Coding, das bringt nur nicht viel.
Wenn du die Daten in der Tabelle meinst:
Nein, die stehen ja nicht im Code.
Von daher geht das leider nicht, bzw. nicht wirklich.
new str[145];
format(str, sizeof(str), "Mein Level: %d", SpielerInfo[playerid][pLevel]);
SendClientMessage(playerid, 0xFF0000FF, str);
Siehe hierzu:
https://wiki.sa-mp.com/wiki/Format
Ok, dann ändere
FactionCars[fc][fPrice] = FactionBuylist[fc][fbPrice];
zu:
for(new i = 0; i < sizeof(FactionBuylist); i++)
{
if(FactionCars[fc][fVehid] == FactionBuylist[i][fbVehid])
{
FactionCars[fc][fPrice] = FactionBuylist[i][fbPrice];
break;
}
}
So wird dann immer der Preis zum entsprechenden Model gefunden.
PS: Den Code mit dem Motorschaden beim Laden musst du etwas weiter nach unten schieben, nach CreateVehicle, sonst setzt er die Health des Fahrzeugs bevor es erstellt ist, das geht nicht.
Du kannst auch den Spieler am einsteigen hindern, indem du TogglePlayerControllable nutzt.
Bei OnPlayerEnterVehicle:
TogglePlayerControllable(playerid, false);
TogglePlayerControllable(playerid, true);
Natürlich nur bei den vehicleids, die im Autohaus stehen.
Damit die Fahrzeuge nicht bewegt werden können kannst du ja auf OnUnoccupiedVehicleUpdate zurück greifen.
Strings über Arrays kannst du nicht direkt zuweisen. Nutze anstatt sowas
Rangname[idx][Rang1] = temp;
Sowas:
format(Rangname[idx][Rang1], 32, temp);
Alternativ geht es auch mit strcat.
Beim Laden der Fahrzeuge soll dann der Preis wieder ermittelt werden, so wie das aussieht, oder?
Der Preis soll anhand der Model ID gefunden werden? Oder kann es vorkommen, dass in der FactionBuylist ein Model zwei mal vorkommt?
Zu was denn?
Zu dem Rangbezeichner?
Das habe ich dir ja geschrieben.
Dort, wo sich der Rang ändert, das hier einfügen:
LOLTIMER(playerid);
Den SetTimer zu LOLTIMER komplett entfernen. Somit wird das Textdraw nur dann geändert, wenn es auch geändert werden muss.
Ein Beispiel zu was?
wie soll ich das den machen
Dort wo sich der Rang ändert:
LOLTIMER(playerid);
Dann wird die Funktion nur dann einmal aufgerufen, wenn sie es soll. Und beim Login eventuell.
kannst du mir bei diesem problem helfen ?
Die Funktion existiert bei dir nicht. Nutze mysql_query und lese das Ergebnis danach aus, wie im Code oben.
Bei der Hitze?
![]()
Lieber zu früh als zu spät - geht ja nicht kaputt ![]()
B2T:
6 Displayschutzfolien fürs Handy beu schutzfolien24 für 1,99€.
Klar. Zum Beispiel so:
string[0] = EOS;
Oder so:
string[0] = '\0';
Gibt noch weitere Möglichkeiten, so ist es aber am schnellsten.
Wie ist denn FactionBuylist deklariert, und wie sehen die Werte dazu aus?
Das solltest du nicht per Timer machen, sondern die Funktion dort aufrufen, wo der Rang geändert wird.
Sonst spricht der Code ja ständig die Datenbank an. Bei mehreren Spielern wird das ziemlich ressourcenlastig.