[Y_INI] Durch alle Spielerdaten loopen

Wichtiger Hinweis: Bitte ändert nicht manuell die Schriftfarbe auf schwarz sondern belasst es bei der Standardeinstellung. Somit tragt ihr dazu bei dass euer Text auch bei Verwendung unseren dunklen Forenstils noch lesbar ist!

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


    ich habe folgendes vor:
    Jeden Tag um 00:00Uhr (Callback dafür existiert bereits, daran hapert es also nicht), soll jedem Spieler ein gewisser Betrag von seinem Bankkonto abgezogen wird, je nachdem, was für einen Accountlevel er/sie hat.


    Beispiel:
    Spieler X ist auf Level 0: 100$ Abzug.
    Spieler Y ist auf Level 2: 300$ Abzug.


    Es müssen also alle Spielerdateien im Ordner "Users" durchloopt werden, alle einzeln geöffnet werden und die eine Variable abgeändert werden.


    Das hier habe ich soweit.
    forward OnServerTime(hours, minutes);
    public OnServerTime(hours, minutes)
    {
    hour = hours;
    minute = minutes;

    if(hours == 0 && minutes == 0)
    {
    for(new i = 0; i < MAX_PLAYERS; i++)
    {
    switch(pInfo[i][BankAccount])
    {
    case BANK_JUNIOR_ACCOUNT: pInfo[i][Bank] -= DEDUCTION_JUNIOR_ACCOUNT;
    case BANK_WORKER_ACCOUNT: pInfo[i][Bank] -= DEDUCTION_WORKER_ACCOUNT;
    case BANK_CHIEF_ACCOUNT: pInfo[i][Bank] -= DEDUCTION_CHIEF_ACCOUNT;
    case BANK_BUSINESS_ACCOUNT: pInfo[i][Bank] -= DEDUCTION_BUSINESS_ACCOUNT;
    }
    }
    }
    return 1;
    }

  • Was du da vor hast ist eine ganz schlechte Idee. Willst du wirklich alle Spieler die registriert sind durchloopen?
    Stell dir mal vor wenn du 10.000 Accounts hast (und das geht schnell, ca. 1/2 Jahr bei mir, pro 10.000 Accounts). Es muss um diese Zeit dann jede Datei geöffnet werden, sprich 10.000 Dateiöffnungen, Daten auslesen, Daten schreiben und dann die Datei wieder speichern.
    Du kannst das ja testweise mal mit einer Datei testen, und diese 10.000 Mal öffnen, auslesen, beschreiben und dann wieder speichern. Dann sieh dir die Zeit an wie lange das dauert.


    Generell:
    Wenn du das machen willst, dann nutze das FileManager Plugin, damit geht es auf jeden Fall.


    Oder, und das ist die wesentlich bessere Variante für dieses Vorhaben, nutze MySQL.


    ODER, und das ist die allerbeste Variante:
    Ziehe dem Spieler das Geld ab, wenn er auf den Server kommt und sich einloggt, direkt beim einloggen.
    Wie? Du berechnest die Tage die er nicht mehr online war und ziehst ihm dann X mal den Wert ab, den er abgezogen bekommen soll.

  • Beitrag von Dog ()

    Dieser Beitrag wurde gelöscht, Informationen über den Löschvorgang sind nicht verfügbar.
  • Dass das eine absolut suboptimale Lösung ist, war mir von Anfang an klar.^^


    Hm, also kann ich das ganze dann per timestamp machen, wenn der Spieler zur Abrechnungszeit 00:00Uhr offline ist? Wenn er dann online ist, ist das ganze ja kein Problem.
    Wie berechne ich die Zeit, die er offline war am besten? Timestamp beim Logout in die Userfile schreiben, und beim Login wieder auslesen und auswerten?

  • Wenn du solche Berechnungen nutzt solltest du auf jeden Fall auf MySQL o.ä. umsteigen. Da lässt es sich mit einem SQL machen, dann passt das.


    Wenn du es wirklich mit Datein lösen möchtest, dann kannst du das mit dem Timestamp so machen. Ich würde so ran gehen das ich erst einmal prüfe ob die Person heute schon online war. Sprich Timestamp heute 0:00:00 mit letzten Logout vergleichen wenn der heutige Timestamp größer ist dann war er heute noch nicht online. Und dann rechnest du einfach nach wie viele Tage er offline war.


    Ich hoffe es ist verständlich geschrieben ^^

  • Die Berechnung ist ziemlich einfach.


    Du speicherst global den Timestamp wenn es 0 Uhr ist und du speicherst den momentanen Timestamp in die Spielerdatei wenn er den Server verlässt.
    Den globalen Timestamp solltest du für den Fall eines Server Neustarts in einer Einstellungsdatei speichern und beim Start des Servers laden.


    Beim Login berechnest du dann, wenn der Timestamp on der Spielerdatei kleiner ist als der global gespeicherte:
    tage = ((global - Datei)/86400) + 1


    Das wären die Tage, die er zahlen muss.
    Gegebenenfalls kann man auch noch eine Schleife machen, die es den Spielern die online sind direkt abzieht.


    Ich denke, die Codes dazu bekommst du hin.
    Falls Probleme auftreten, einfach nachfragen!

  • Warum willst du das ganze über den SA:MP Server überhaupt erledigen? Schreib dir z.B. nen PHP Script, das mittels Cronjob zum Ausführzeitpunkt aufgerufen werden. Die Inhalte kannst du dir ja zusammengooglen. Damit beschäftigst du wenigstens dann nicht deinen SA:MP Server, der ohnehin schon ohne solche Sachen ausgelastet genug sein wird.

  • Okay, also...


    1. Den Timestamp von 00:00Uhr global abspeichern.
    new NewDay;


    public OnServerTime(hours, minutes)
    {
    hour = hours;
    minute = minutes;


    if(hours == 0 && minutes == 0)
    {
    NewDay = gettime();
    new INI:config = INI_Open("NewDay.cfg");
    INI_WriteInt(config, "Midnight", NewDay);
    INI_Close(config);


    for(new i = 0; i < MAX_PLAYERS; i++)
    {
    if(IsPlayerOnline(i))
    {
    switch(pInfo[i][BankAccount])
    {
    case BANK_JUNIOR_ACCOUNT: pInfo[i][Bank] -= DEDUCTION_JUNIOR_ACCOUNT;
    case BANK_WORKER_ACCOUNT: pInfo[i][Bank] -= DEDUCTION_WORKER_ACCOUNT;
    case BANK_CHIEF_ACCOUNT: pInfo[i][Bank] -= DEDUCTION_CHIEF_ACCOUNT;
    case BANK_BUSINESS_ACCOUNT: pInfo[i][Bank] -= DEDUCTION_BUSINESS_ACCOUNT;
    }
    }
    }
    }
    return 1;
    }


    Frage dazu: Wie speicher ich den aktuellen Timestamp in einer config Datei ab? Passt das so?

  • Es wäre besser, wenn du den Tageswechsel nicht über Stunde und Minute prüfst, da es ja durchaus mal vorkommen kann, dass dein Server um genau 0 Uhr aus ist, warum auch immer.
    Außerdem könnte es ja sein, dass der Timer zwei mal um 0:00 aufgerufen wird, dann würde es zwei mal die Steuern abziehen.


    Daher ist es besser, wenn du es so machst:


    new newDay; //Diese beiden musst du natürlich bei OnGameModeInit aus der cfg Datei laden.
    new oldDay;


    public OnServerTime(hours, minutes) //Brauchst du die Werte?
    {
    new y,m,d;
    getdate(y,m,d);
    if(d != oldDay) //Wenn es ein anderer Tag ist
    {
    oldDay = d;
    new timestamp = gettime() - 86400;
    while(newDay <= timestamp) newDay += 86400; //Damit es immer den 0:00:00 Timestamp speichert.
    new INI:config = INI_Open("NewDay.cfg");
    INI_WriteInt(config, "Midnight", newDay);
    INI_WriteInt(config, "oldDay", oldDay);
    INI_Close(config);


    for(new i = 0; i < MAX_PLAYERS; i++)
    {
    if(IsPlayerOnline(i))
    {
    switch(pInfo[i][BankAccount])
    {
    case BANK_JUNIOR_ACCOUNT: pInfo[i][Bank] -= DEDUCTION_JUNIOR_ACCOUNT;
    case BANK_WORKER_ACCOUNT: pInfo[i][Bank] -= DEDUCTION_WORKER_ACCOUNT;
    case BANK_CHIEF_ACCOUNT: pInfo[i][Bank] -= DEDUCTION_CHIEF_ACCOUNT;
    case BANK_BUSINESS_ACCOUNT: pInfo[i][Bank] -= DEDUCTION_BUSINESS_ACCOUNT;
    }
    }
    }
    }
    return 1;
    }


    Und dann eben noch beim Login prüfen, wie viele Tage zwischen newDay und dem Logout des Spielers liegen und entsprechend das Geld abziehen.

  • Ich bin mir jetzt noch nicht ganz so im Klaren darüber, wie ich den Timestamp auf der config Datei "lade". Ich habe mir mal die Y_INI Dokumentation durchgelesen und bin mehr als verwirrt... Fällt das Auslesen nun unter "Loading" oder "Reading"?

  • Ich hab mich jetzt mal dazu entschlossen keinen festen Betrag jeden Tag abzuziehen, sondern monatlich einen prozentualen. Allerdings habe ich hier ein Problem - die Abgaben können umgangen werden. Wenn man am letzten Tag des Monats das gesamte Geld von seinem Konto abhebt, ist die Steuer gleich 0. Wie könnte ich dem geschickt entgegenwirken...?

  • Ich hab mich jetzt mal dazu entschlossen keinen festen Betrag jeden Tag abzuziehen, sondern monatlich einen prozentualen. Allerdings habe ich hier ein Problem - die Abgaben können umgangen werden. Wenn man am letzten Tag des Monats das gesamte Geld von seinem Konto abhebt, ist die Steuer gleich 0. Wie könnte ich dem geschickt entgegenwirken...?


    Du kannst ja seine Transaktionen speichern.

  • Beim monatlichen Durchschnitt fürchte ich, dass dieser leicht beeinflusst werden kann. Folgendes Beispiel:


    Nehmen wir an, der Spieler hat 1.000.000$ auf seinem Konto. Nun muss der monatliche Durchschnitt ja bei jeder Transaktion (Einzahlen, Abheben) neu berechnet werden.
    Ein Spieler, der keine Transaktion durchführt hat im Schnitt, nach wie vor, 1.000.000$.
    Ein Spieler, der das Geld draufzahlt, abhebt, und wieder draufzahlt, hat also insgesamt 3 Kontostände gehabt: 1.000.000$, dann 0$ und wieder 1.000.000$.
    Im Schnitt hat dieser Spieler dann ein Durchschnittsvermögen von 2.000.000/3 = 666.667$, was eine erhebliche Minussumme ist.


    Deswegen hab ich mir gedacht, dass das monatliche Maximum versteuert wird. Daran kann schlecht gepfuscht werden.
    enum PlayerInfo
    {
    //...
    MonthlyBankMax
    }


    //aus dem enum ergibt sich dann...
    pInfo[playerid][MonthlyBankMax];


    Nun bringt mir mein OnServerTime callback in diesem Zusammenhang nichts mehr. Ich brauche ein Callback, dass beim Umschwung von Tagen, Monaten und Jahren aufgerufen wird. Oder brauche ich da überhaupt ein Callback? Ich stell das ja mit getdate() an, aber wie am sinnvollsten?


    An diesem Punkt möchte ich mich mal bedanken, dass ihr mir helft!

  • Du prüfst einfach überall wo sich das Geld ändert:
    if(pInfo[playerid][Geld] > pInfo[playerid][MonthlyBankMax]) pInfo[playerid][MonthlyBankMax] = pInfo[playerid][Geld];


    Mehr musst du da eigentlich nicht machen.


    Das berechnet dann ja den Durchschnitt von dem Konto und dem, was der Spieler auf der Hand hat, und das ist ja eigentlich nicht das, was ich erreichen möchte. ;)
    Das Geld auf der Hand soll unversteuert bleiben.


    Nur, um mal bisschen Licht ins Dunkle zu bringen: das System soll Inflation auf einem Freeroam Server mit ein paar RL Elementen vorbeugen.