[jTuT] Fraktions-Fahrzeug-System mit Dini 1.6
Hallo zusammen,
da mir einige Male die Frage gestellt wurde, ob ich zu dem Fraktions-Fahrzeug-System basierend auf MySQL auch eines auf Dini basierend machen oder zeigen könnte, und ich kein vernünftiges Tutorial gefunden habe, poste ich jetzt selbst eines. Gerne kann dieser Thread auch für Fragen bezüglich dem System oder eventuellen Änderungen verwendet werden.
Voraussetzungen:
- Einzigste Voraussetzung für dieses Tutorial ist ein vorhandenes Fraktionssystem
Kurzer Überblick:
- Dieses Tutorial beschreibt und erklärt die Erstellung von Fahrzeugen, die nur von einer bestimmten Fraktion verwendet werden können. Außerdem wird der Aufbau der Dateien, sowie das Laden und das Speichern der Fahrzeuge erklärt. Am Ende haben wir ein komplett funktionsfähiges Fraktions-Fahrzeug-System welches auf DracoBlue's Dini 1.6 basiert. Falls Du die Include noch nicht hast, lade es Dir bitte jetzt herunter und füge sie 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.
Wir arbeiten uns durch den Code:
- Erstelle bitte als erstes im scriptfiles-Ordner deines Server den Ordner, in dem später die Fraktions-Fahrzeuge gespeichert werden. Wir nennen ihn "fracVehicles".
- Füge anschließend, falls Du das noch nicht hast, die Dini-Include ganz oben in Deinen Code ein:
- Zuerst müssen wir uns überlegen, welche Daten wir in der Datei speichern möchten. Bei diesem Fahrzeug-System nehmen wir der Einfachheit halber die gängingsten Daten, die da wären:
Model-ID, X, Y, Z, Rotation, Farbe1, Farbe2 und die FraktionsID
Natürlich können weitere Daten beliebig hinzugefügt werden. - Außerdem benötigen wir einen Speicherplatz für die später erstellten Fahrzeuge, das machen wir nach mit einem Enum und einer zweidimensionalen Variable. Dazu benötigen wir noch einen Maximal-Wert, den wir hier mit 10 definieren, das kann aber beliebig geändert werden (beachte das Limit an maximal erstellbaren Fahrzeugen (MAX_VEHICLES)).C
Alles anzeigen#define MAX_FRAC_VEHICLES 10 enum fracVehEnum { e_modelID, Float:e_x, Float:e_y, Float:e_z, Float:e_a, e_color1, e_color2, e_fracID, e_vID }; new fracVehicle[MAX_FRAC_VEHICLES][fracVehEnum];
Daten können entweder direkt in die Datei eingetragen werden, oder mit den Befehlen erstellt/gelöscht werden, die wir später zusammen erstellen.
In der Datei sieht das dann später zum Beispiel so aus: - Jetzt erstellen wir die Funktion, die zum Serverstart die Daten aus den Dini-Datein lädt.
Hinweis: Ich verwende "floatstr" anstatt dini_Float, da dini_Float einen Tag-Mismatch verursacht.C
Alles anzeigenLoadFracVehicles() { //Deklaration neuer temporärer Variablen: new createdVehs, path[64]; //Schleife durch alle Dateien: for(new i=0; i<MAX_FRAC_VEHICLES; i++) { //Es wird geprüft, ob ein Fahrzeug mit der ID existiert, wenn nicht, wird diese ID übersprungen format(path, sizeof(path), "/fracVehicles/%d.ini", i); if(!fexist(path)) continue; //Fahrzeug existiert im fracVehicles-Ordner, wir laden die Daten jetzt aus der Datei. fracVehicle[i][e_modelID] = dini_Int(path, "modelID"); fracVehicle[i][e_x] = floatstr(dini_Get(path, "x")); fracVehicle[i][e_y] = floatstr(dini_Get(path, "y")); fracVehicle[i][e_z] = floatstr(dini_Get(path, "z")); fracVehicle[i][e_a] = floatstr(dini_Get(path, "a")); fracVehicle[i][e_color1] = dini_Int(path, "color1"); fracVehicle[i][e_color2] = dini_Int(path, "color2"); fracVehicle[i][e_fracID] = dini_Int(path, "fracID"); //Zur Sicherheit fragen wir hier nun ab, ob das angegebene Modell auch existiert, //sollte das nicht der Fall sein, dann wird das Fahrzeug nicht erstellt. if(fracVehicle[i][e_modelID] >= 400 && fracVehicle[i][e_modelID] <= 611) { //Nachdem das Fahrzeug geladen wurde, wird es erstellt. fracVehicle[i][e_vID] = CreateVehicle(fracVehicle[i][e_modelID], fracVehicle[i][e_x], fracVehicle[i][e_y], fracVehicle[i][e_z], fracVehicle[i][e_a], fracVehicle[i][e_color1], fracVehicle[i][e_color2], -1); } else { //Falls eine nicht existierende Model-ID angegeben wurde, geben wir eine Information aus. printf("[Error] Model-ID %d existiert nicht (ID: %d).", fracVehicle[i][e_modelID], i); } //Zur Sicherheit fragen wir noch ab, ob das Fahrzeug-Limit noch nicht überschritten wurde. //Existiert ein Fahrzeug mit der höchsten ID, dann kann kein weiteres mehr erstellt werden. if(GetVehicleModel(MAX_VEHICLES-1) != 0) return print("Es können keine weiteren Fahrzeuge geladen werden, Limit (MAX_VEHICLES) erreicht."); //Zur weiteren Sicherheit prüfen wir noch, ob die maximale Anzahl an Fraktions-Fahrzeugen erreicht ist. createdVehs++; if(createdVehs == MAX_FRAC_VEHICLES) return print("Es können keine weiteren Fahrzeuge geladen werden, Limit (MAX_FRAC_VEHICLES) erreicht."); } return 1; }
Füge diese Funktion ganz unten in Deinem Gamemode/Filterscript ein.
Unter OnGameModeInit beziehungsweise OnFilterScriptInit musst Du dann folgendes einfügen:
Damit hätten wir das Laden erledigt. - Unser Fahrzeug wird nun also erstellt, falls es existiert. Jetzt müssen wir die Daten natürlich nach einer eventuellen Änderung speichern lassen. Dazu eignet sich zum Beispiel ein Timer, der jede Minute alle Fahrzeuge speichert.
Dazu erstellen wir bei OnGameModeInit/OnFilterScriptInit einen Timer:
Und ganz unten im Gamemode/Filterscript erstellen wir dazu das Callback:C
Alles anzeigenforward SaveAllFracVehs(); public SaveAllFracVehs() { //Deklaration neuer temporärer Variablen: new path[64]; //Schleife durch alle Fraktions-Fahrzeuge: for(new i=0; i<MAX_FRAC_VEHICLES; i++) { //Wenn das Fahrzeug existiert if(fracVehicle[i][e_modelID] >= 400 && fracVehicle[i][e_modelID] <= 611) { //Es wird der Pfad gesetzt: format(path, sizeof(path), "/fracVehicles/%d.ini", i); //Wir fragen die Position des Fahrzeugs ab: GetVehiclePos(fracVehicle[i][e_vID], fracVehicle[i][e_x], fracVehicle[i][e_y], fracVehicle[i][e_z]); GetVehicleZAngle(fracVehicle[i][e_vID], fracVehicle[i][e_a]); //Und wir speichern die Daten: dini_IntSet(path, "modelID", fracVehicle[i][e_modelID]); dini_FloatSet(path, "x", fracVehicle[i][e_x]); dini_FloatSet(path, "y", fracVehicle[i][e_y]); dini_FloatSet(path, "z", fracVehicle[i][e_z]); dini_FloatSet(path, "a", fracVehicle[i][e_a]); dini_IntSet(path, "color1", fracVehicle[i][e_color1]); dini_IntSet(path, "color2", fracVehicle[i][e_color2]); dini_IntSet(path, "fracID", fracVehicle[i][e_fracID]); } } return 1; }
Diese Funktion kann natürlich auch bei OnGameModeExit/OnFilterScriptExit eingefügt werden, falls gewünscht.
Dazu einfach
verwenden.
Ebenso kann dort optional noch eingebaut werden, dass alle Fahrzeuge aus dem Server entfernt werden (nicht die Dateien), falls der Code beendet wird.C//Schleife durch alle Fraktions-Fahrzeuge: for(new i=0; i<MAX_FRAC_VEHICLES; i++) { //Wenn das Fahrzeug existiert if(fracVehicle[i][e_modelID] >= 400 && fracVehicle[i][e_modelID] <= 611) { DestroyVehicle(fracVehicle[i][e_vID]); } }
Hinweis: Je nach dem wie viele Fahrzeuge erstellt werden macht es mehr oder weniger Sinn einen Timer zu verwenden. Bei 100 Fahrzeugen ist das kein Problem, hat man aber zum Beispiel 1000 Fahrzeuge, dann kann aufgrund der 1000 gleichzeitig ausgeführten Speicherungen Lag entstehen, beziehungsweise der Server kurzzeitig eingefroren sein. Dann sollte man von dieser Methode abstand nehmen und nur auf die nachfolgende Methode zurückgreifen.
- Wenn wir schon dabei sind, dann können wir auch gleich noch eine Funktion erstellen, die ein Fahrzeug anhand seiner Vehicle ID speichern kann, sofern es ein Fraktions-Fahrzeug ist. Diese Funktion sieht dann so aus:C
Alles anzeigenstock SaveFracVehCheck(vehicleid) { //Deklaration neuer temporärer Variablen: new path[64]; //Schleife durch alle Fraktions-Fahrzeuge for(new i=0; i<MAX_FRAC_VEHICLES; i++) { //Wenn die vehicleid die gleiche ist, wie die des Fraktions-Fahrzeugs if(fracVehicle[i][e_vID] == vehicleid) { //Es wird der Pfad gesetzt: format(path, sizeof(path), "/fracVehicles/%d.ini", i); //Wir fragen die Position des Fahrzeugs ab: GetVehiclePos(fracVehicle[i][e_vID], fracVehicle[i][e_x], fracVehicle[i][e_y], fracVehicle[i][e_z]); GetVehicleZAngle(fracVehicle[i][e_vID], fracVehicle[i][e_a]); //Und wir speichern die Daten: dini_IntSet(path, "modelID", fracVehicle[i][e_modelID]); dini_FloatSet(path, "x", fracVehicle[i][e_x]); dini_FloatSet(path, "y", fracVehicle[i][e_y]); dini_FloatSet(path, "z", fracVehicle[i][e_z]); dini_FloatSet(path, "a", fracVehicle[i][e_a]); dini_IntSet(path, "color1", fracVehicle[i][e_color1]); dini_IntSet(path, "color2", fracVehicle[i][e_color2]); dini_IntSet(path, "fracID", fracVehicle[i][e_fracID]); return 1; //Es gibt ja keine zwei gleichen Fahrzeuge } } return 0; //Fahrzeug ist kein Fraktions-Fahrzeug }
Das können wir, wenn wir es schon haben, bei OnPlayerExitVehicle einbauen, damit das Fahrzeug gespeichert wird, wenn ein Spieler es verlässt.
Dazu einfach bei OnPlayerExitVehicle das einfügen:
Alternativ kann man auch einen /parken Befehl erstellen, durch den man die neue Position speichert.
Das könnte dann so aussehen:Cnew vehicleid = GetPlayerVehicleID(playerid); if(SaveFracVehCheck(vehicleid)) return SendClientMessage(playerid, 0x00FF00FF, "Fahrzeug geparkt."); else return SendClientMessage(playerid, 0xFF0000FF, "Dieses Fahrzeug kann nicht geparkt werden.");
Je nach Server ist das eine oder das andere sinnvoll. Man kann es aber auch ganz anders machen, das bleibt jedem selbst überlassen. - Falls sich die Farben der Fahrzeuge ändern können, dann müssen an entsprechender Stelle auch die Werte der Variablen geändert werden.
Dies macht man beispielsweise so:C
Alles anzeigen//Eine Schleife durch alle Fraktions-Fahrzeuge for(new i=0; i<MAX_FRAC_VEHICLES; i++) { //Wenn die vehicleid die gleiche ist, wie die des Fraktions-Fahrzeugs if(fracVehicle[i][e_vID] == vehicleid) { //Dann ändere die Farbe. fracVehicle[i][e_color1] = color1; fracVehicle[i][e_color1] = color2; break; //Es gibt ja keine zwei gleichen Fahrzeuge } }
Je nach dem an welcher Stelle das bei Dir im Code relevant ist, das können viele Stellen sein, muss aber nicht.
Damit hätten wir den größten Teil eigentlich auch schon hinter uns. Es fehlt nur noch eine Kleinigkeit. - In diesem Tutorial geht es ja darum, Fraktions-Fahrzeuge zu erstellen. Momentan kann unsere Fahrzeuge aber noch jeder betreten, daher müssen wir jetzt bei OnPlayerEnterVehicle noch folgendes hinzufügen:C
Alles anzeigen//Eine Schleife durch alle Fraktions-Fahrzeuge for(new i=0; i<MAX_FRAC_VEHICLES; i++) { //Wenn die vehicleid die gleiche ist, wie die des Fraktions-Fahrzeugs if(fracVehicle[i][e_vID] == vehicleid) { //Jetzt brauchen wir die Variable, mit der Dein vorher bereits existierendes Fraktions-System arbeitet. //Ich nehme jetzt einfach eine Beispiel-Variable, diese musst Du selbst mit der ersetzen, //die Dein System verwendet. //Es geht um diese Variable: PlayerInfo[playerid][pFraction] if(PlayerInfo[playerid][pFraction] != fracVehicle[i][e_fracID]) { //Wenn der Spieler nicht in der Fraktion ist, die das Fahrzeug verwenden darf, //dann darf er es nicht betreten. TogglePlayerControllable(playerid, false); TogglePlayerControllable(playerid, true); SendClientMessage(playerid, 0xFF0000FF, "Du bist nicht in der Fraktion, die dieses Fahrzeug verwenden darf."); } break; //Es gibt ja keine zwei gleichen Fahrzeuge } }
Wie gesagt, dieser Code muss bei OnPlayerEnterVehicle eingefügt werden. - Jetzt könnten wir eigentlich den Server starten und alles funktioniert einwandfrei. Allerdings müssen wir die Daten für die Fraktions-Fahrzeuge immer mühselig manuell in die Datenbank eintragen, und das macht ja recht wenig Sinn. Deshalb erstellen wir jetzt noch einen Befehl um Fraktions-Fahrzeuge im Spiel zu erstellen und einen Befehl um Fraktions-Fahrzeuge zu löschen. Im Beispiel nutze ich ocmd. Falls Du einen anderen verwendest kannst du dies einfach umschreiben.
Außerdem verwende ich in den Beispielen strtok, da dies ohne Plugin realsierbar ist und somit eine höhere Funktionalität gewährleistet. Ich musste die Funktion strtok zu strtok2 umbenennen, da bei Dini zum Teil strtok bereits inkludiert ist, allerdings mit anderen Array-Größen.
Die beiden Funktionen:C
Alles anzeigenstock strtok2(const string[], &index) //©Jeffry { new result[20], length = strlen(string), i = index; while ((i < length) && (string[i] == ' ')) i++; strmid(result,string,i,((index = strfind(string, " ", false, i)) == -1) ? (index = length) : (index) , 20); index++; return result; } stock IsNumeric(string[]) { for (new i = 0, j = strlen(string); i < j; i++) { if ((string[i] > '9' || string[i] < '0')) return 0; } return 1; }
Fraktions-Fahrzeuge erstellen:
C
Alles anzeigenocmd:fferstellen(playerid, params[]) { //Zuerst fragen wir ab, ob wir noch Fahrzeuge erstellen können if(GetVehicleModel(MAX_VEHICLES-1) != 0) return SendClientMessage(playerid, 0xFF0000FF, "Es können keine weiteren Fahrzeuge erstellt werden, Limit (MAX_VEHICLES) erreicht."); //Wir deklarieren die benötigten temporären Variablen. new tmp[20], idx, model, fID, color1 = -1, color2 = -1; //Anschließend teilen wir mit strtok2 die eingegebenen Paramater auf und wandeln sie in eine Zahl um. //Falls etwas falsches eingegeben wurde, geben wir eine entsprechende Meldung zurück. tmp = strtok2(params, idx); if(!strlen(tmp) || !IsNumeric(tmp)) return SendClientMessage(playerid, 0xFF0000FF, "Verwendung: /fferstellen [Model] [FraktionsID] [opt:Farbe1] [opt:Farbe2]"); model = strval(tmp); //Eine solche Abfrage kann man auch für nachfolgende FraktionsID (fID) machen, falls gewünscht. if(model < 400 || model > 611) return SendClientMessage(playerid, 0xFF0000FF, "Error: Model ID existiert nicht."); tmp = strtok2(params, idx); if(!strlen(tmp) || !IsNumeric(tmp)) return SendClientMessage(playerid, 0xFF0000FF, "Verwendung: /fferstellen [Model] [FraktionsID] [opt:Farbe1] [opt:Farbe2]"); fID = strval(tmp); tmp = strtok2(params, idx); if(strlen(tmp) && IsNumeric(tmp)) color1 = strval(tmp); tmp = strtok2(params, idx); if(strlen(tmp) && IsNumeric(tmp)) color2 = strval(tmp); //Sind alle Parameter korrekt übergeben worden, dann suchen wir uns einen freien Index in den wir das Fraktions-Fahrzeug speichern können. for(new i=0; i<MAX_FRAC_VEHICLES; i++) { //Frei: if(fracVehicle[i][e_vID] == 0) { //Daten werden übergeben new Float:x, Float:y, Float:z, Float:a; GetPlayerPos(playerid, x, y, z); GetPlayerFacingAngle(playerid, a); fracVehicle[i][e_modelID] = model; fracVehicle[i][e_x] = x; fracVehicle[i][e_y] = y; fracVehicle[i][e_z] = z; fracVehicle[i][e_a] = a; fracVehicle[i][e_color1] = color1; fracVehicle[i][e_color2] = color2; fracVehicle[i][e_fracID] = fID; //und anschließend wird dann das Fahrzeug erstellt und der Spieler in das Fahrzeug gesetzt. fracVehicle[i][e_vID] = CreateVehicle(fracVehicle[i][e_modelID], fracVehicle[i][e_x], fracVehicle[i][e_y], fracVehicle[i][e_z], fracVehicle[i][e_a], fracVehicle[i][e_color1], fracVehicle[i][e_color2], -1); PutPlayerInVehicle(playerid, fracVehicle[i][e_vID], 0); //Zuletzt wird die Datei angelegt und das Fahrzeug gespeichert. new path[64]; format(path, sizeof(path), "/fracVehicles/%d.ini", i); dini_Create(path); SaveFracVehCheck(fracVehicle[i][e_vID]); return SendClientMessage(playerid, 0x00FF00FF, "Fahrzeug gespeichert."); } } return SendClientMessage(playerid, 0xFF0000FF, "Error: Limit für Fraktions-Fahrzeuge erreicht."); }
Fraktions-Fahrzeuge löschen:
C
Alles anzeigenocmd:ffloeschen(playerid, params[]) { //Wir deklarieren die benötigte temporäre Variable. new vid; //Wenn der Spieler keine Vehicle-ID eingibt wird die gelöscht, in der sich der Spieler befindet, //ansonsten die eingegebene ID. if(!IsNumeric(params) || !strlen(params)) return SendClientMessage(playerid, 0xFF0000FF, "Error: Nutze: /ffloeschen [Vehicle ID]"); vid = strval(params); if(vid <= 0) return SendClientMessage(playerid, 0xFF0000FF, "Error: Vehicle-ID ist kein Fraktions-Fahrzeug."); for(new i=0; i<MAX_FRAC_VEHICLES; i++) { //Eingegebene ID und die des Fraktions-Fahrzeugs stimmen überein. if(fracVehicle[i][e_vID] == vid) { //Daten werden entfernt fracVehicle[i][e_modelID] = 0; fracVehicle[i][e_x] = 0.0; fracVehicle[i][e_y] = 0.0; fracVehicle[i][e_z] = 0.0; fracVehicle[i][e_a] = 0.0; fracVehicle[i][e_color1] = 0; fracVehicle[i][e_color2] = 0; fracVehicle[i][e_fracID] = -1; //und anschließend in der Datenbank gelöscht. new path[64]; format(path, sizeof(path), "/fracVehicles/%d.ini", i); dini_Remove(path); DestroyVehicle(fracVehicle[i][e_vID]); fracVehicle[i][e_vID] = 0; return SendClientMessage(playerid, 0x00FF00FF, "Fahrzeug gelöscht."); } } return SendClientMessage(playerid, 0xFF0000FF, "Error: Vehicle-ID ist kein Fraktions-Fahrzeug."); }
Und wenn wir schon dabei sind machen wir auch gleich noch den /parken Befehl komplett:
Cocmd:parken(playerid) { if(!IsPlayerInAnyVehicle(playerid)) return SendClientMessage(playerid, 0xFF0000FF, "Du bist in keinem Fahrzeug."); new vehicleid = GetPlayerVehicleID(playerid); if(SaveFracVehCheck(vehicleid)) return SendClientMessage(playerid, 0x00FF00FF, "Fahrzeug geparkt."); else return SendClientMessage(playerid, 0xFF0000FF, "Dieses Fahrzeug kann nicht geparkt werden."); }
- Damit wären wir durch. Es sind alle notwendigen Teile im Code vorhanden.
Ich hoffe, das System funktioniert bei Dir jetzt wie bei mir ohne Probleme. Wenn nicht, oder wenn irgendwelche Fragen auftreten, bzw. aufgetreten sind, darfst Du diese gerne hier oder in der Scripting Base stellen.
Für die Faulen unter uns:
Natürlich kann man das System weiter ausbauen, und weitere Daten hinzufügen, je nach dem was für den jeweiligen Server passend ist. Das könnten gefahrene Kilometer, Nummerntafeln, Tunings, etc... sein, da gibt es sehr viele Möglichkeiten. Diese kann man alle zimelich einfach hinzufügen. Falls Probleme auftreten, wie gesagt, einfach fragen!
Viel Spaß damit!
Beste Grüße,
Jeffry