maxi-91: Offline Datenbankaktivität

Hallo!

Ich möchte ein Browsergame programmieren und habe dazu folgende Frage:
Wie ändere ich Datenbankwerte, wenn der Spieler offline ist. Also folgendes:
Ein Spieler "verdient" pro Sekunde 5 Geld. Der Spieler geht offline, 20 Minuten danach wird er von einem anderen Spieler angegriffen. Jetzt soll der angreifende Spieler das Geld erhalten, was der angegriffene Spieler hat. Wie kann ich das verwirklichen?

LG
Maxi

Ps.: Über das Konzept usw. habe ich mir schon genug Gedanken gemacht, bitte nur Antworten zum Thema, Dankeschön ;)

  1. Tach auch.

    Ich möchte ein Browsergame programmieren und habe dazu folgende Frage:
    Wie ändere ich Datenbankwerte, wenn der Spieler offline ist. Also folgendes:
    Ein Spieler "verdient" pro Sekunde 5 Geld. Der Spieler geht offline, 20 Minuten danach wird er von einem anderen Spieler angegriffen. Jetzt soll der angreifende Spieler das Geld erhalten, was der angegriffene Spieler hat. Wie kann ich das verwirklichen?

    Für solche zeitbasierten Sachen eignen sich cronjobs ganz gut.
    Ggf. wird es etwas komplizierter, wenn du wirklich Sekundengenau abrechnen willst (da cronjobs idR maximal einmal pro Minute laufen).

    Oder du speicherst den Geldbestand nicht ab, sondern berechnest ihn auf Nachfrage neu. Dazu musst du wissen, wie der Geldbestand zu/abnehmen kann.
    Bsp.

    gps sei die Geldmenge, die der Spieler pro Zeiteinheit erhält, bei dir 5 (Zeiteinheit sekunde).

    Zeitpunkt t0 ist der letzte Zeitpunkt, wo der Spieler angegriffen wurde (d.h., Geldbestand ist hier 0: G(t0) = 0)

    Zeitpunkt T sei jetzt.

    In der Zwischenzeit (t aus [t0,T[) wurde der Spieler nicht angegriffen (s. Definition von t0). Er hat Geld für bestimmte Dinge ausgegeben (etwa gA Geldeinheiten) und er hat Geld verdient. Insgesamt ergibt sich:
    g(T) = g(t0) + (T-t0)*gps - gA
         =   0   + (T-t0)*gps - gA

    Wenn es außer angegriffen werden keine Abgänge gibt, dann einfach
    g(T) = (T-t0)*gps

    Dieser Ansatz dürfte deutlich leichter sein als den Goldbestand jede Sekunde oder so zu aktualisieren, insbesondere, wenn der Goldbestand deutlich seltener abgefragt wird als er sonst neu berechnet werden müsste.

    Bis die Tage,
    Matti

  2. Hello,

    Ich möchte ein Browsergame programmieren und habe dazu folgende Frage:
    Wie ändere ich Datenbankwerte, wenn der Spieler offline ist. Also folgendes:
    Ein Spieler "verdient" pro Sekunde 5 Geld. Der Spieler geht offline, 20 Minuten danach wird er von einem anderen Spieler angegriffen. Jetzt soll der angreifende Spieler das Geld erhalten, was der angegriffene Spieler hat. Wie kann ich das verwirklichen?

    Einfach umbuchen :-)

    Um Bewegungen der Daten zu buchen, legt man im in der klassischen Verfahrensweise einfach "Bewegungsdatensätze" an. Hier müssen also zwei Stück geschrieben werden. Einer belastet das Konto des einen Spielers und der andere schreibt den Betrag dem Konto des anderen Spielers gut.

    Das Gutschreiben bereitet dabei keine Probleme, da hier nur ein Insert ausgeführt werden muss.
    Das Belasten kann dagegen ein Nebenläufigkeitsproblem bereiten, da zuerst abgefragt werden muss, wieviel Geld der Spieler besitzt um dieses dann mit dem nächsten Insert zu belasten (wegzunehmen).

    Die Abfrage und der Insert müssen als atomares Statement gekapselt werden.

    Hier möchte ich mal die (My-)SQL-Profis bitten, Stellung zu nehmen. Kann man ein Insert auf dieselbe Tabelle ausführen, auf dem zuvor (im selben Statement) ein select (sum) stattgefunden hat, bzw. das Select als Subquery des Insert ausführen auf dieselbe Tabelle?

    Wie weit ist speziell MySQL hier?

    Liebe Grüße aus dem schönen Oberharz

    Tom vom Berg

    --
     ☻_
    /▌
    / \ Nur selber lernen macht schlau
    http://bergpost.annerschbarrich.de
    1. Hi!

      Ein Spieler "verdient" pro Sekunde 5 Geld. Der Spieler geht offline, 20 Minuten danach wird er von einem anderen Spieler angegriffen. Jetzt soll der angreifende Spieler das Geld erhalten, was der angegriffene Spieler hat. Wie kann ich das verwirklichen?
      Einfach umbuchen :-)

      Wenn nichts stattgefunden hat, seit der Spieler offline gegangen ist, kann man auch von dessen nicht vorhandenem Ergebnis nichts umbuchen. Der angreifende Spieler kann nur das Geld bekommen, dass der angegriffene beim Abmelden hatte. Wo die Differenz herkommt ist ja gerade das Problem. Das ist aber ein grundlegendes und hat nichts mit dem Angriff zu tun. Die Einkünfte müssten ja auch wenn der Spieler online ist, regelmäßig berechnet werden.

      Cronjobs wurden schon erwähnt, aber die halte ich ebenfalls für ungeeignet. Einerseits dass das kleinste Intervall 1 Minute ist, kann anderseits so eine Ausführung wegen $grund ja auch mal ausfallen. Als besser sehe ich es an, wenn zum Zeitpunkt wo jemand abfragt, wieviel Geld da ist, dieses aus dem gespeicherten Kontostand zum ebenfalls gespeicherten Zeitpunkt X und der Differenz zu jetzt plus dem zu errechnenden Zuwachs in der Zeit, ermittelt wird. Das Ergebnis kann man ja nun mit einem Buchungsdatensatz zu den Kontobewegungen hinzufügen:

      Datum: Zeitstempel; Buchungsvorgangstext: Einkünfte für Y Zeiteinheiten seit X; Betrag: + Z Geld

      Dann der Angriff:
      Datum: Zeitstempel; Buchungsvorgangstext: Angreifer Foo plünderte; Betrag: - SUM() Geld

      Wenn man über die Betrag-Spalte ein SUM() laufen lässt, muss nun 0 rauskommen, beziehungsweise der jeweilige Kontostand.

      Damit nicht zu viele Buchungsdatensätze für Mini-Zeiträume stattfinden, in denen eigentlich nichts passiert als dass jemand wisen will, wie der Stand ist, kann man ja einfach nur rechnen und einen Differenzdatensatz erst bei wichtigen Ereignissen erstellen.

      Das Belasten kann dagegen ein Nebenläufigkeitsproblem bereiten, da zuerst abgefragt werden muss, wieviel Geld der Spieler besitzt um dieses dann mit dem nächsten Insert zu belasten (wegzunehmen).
      Die Abfrage und der Insert müssen als atomares Statement gekapselt werden.

      Es bietet sich hier an, das volle Ballett von MySQL zu nutzen: Stored Procedures/Functions und Transaktionen (oder zumindest Table Locking).

      Hier möchte ich mal die (My-)SQL-Profis bitten, Stellung zu nehmen. Kann man ein Insert auf dieselbe Tabelle ausführen, auf dem zuvor (im selben Statement) ein select (sum) stattgefunden hat, bzw. das Select als Subquery des Insert ausführen auf dieselbe Tabelle?

      Ich bin kein Profi, ich habe nur Erfahrung und weiß wo es steht. Man kann kein Update auf eine Tabelle machen, wenn man die Daten mit einem Subselect aus der selben Tabelle holt (vorletzter Satz der verlinkten Stelle). Bei den Subquerys (vorletzter Abschnitt) steht, dass es generell nicht bei Daten ändernden Operationen geht. Es gibt aber eine Ausnahme und das ist INSERT ... SELECT, denn das verwendet implizit eine temporäre Tabelle (dritter Punkt zweiter Absatz).

      Lo!

      1. Hello,

        wie er sein Spiel zu gestalten hat, habe ich als anderes Problem erstmal ausgeblendet.

        Ich bin kein Profi, ich habe nur Erfahrung und weiß wo es steht. Man kann kein Update auf eine Tabelle machen, wenn man die Daten mit einem Subselect aus der selben Tabelle holt (vorletzter Satz der verlinkten Stelle). Bei den Subquerys (vorletzter Abschnitt) steht, dass es generell nicht bei Daten ändernden Operationen geht. Es gibt aber eine Ausnahme und das ist INSERT ... SELECT, denn das verwendet implizit eine temporäre Tabelle (dritter Punkt zweiter Absatz).

        Das ist fein, dass das jetzt erlaubt ist.

        The target table of the INSERT statement may appear in the FROM clause of the SELECT part of the query. (This was not possible in some older versions of MySQL.) However, you cannot insert into a table and select from the same table in a subquery.

        Ich bekomme aber trotzdem immer diese Fehlermelgung:

        ERROR 1093 (HY000): You can't specify target table 'zahl' for update in FROM clause

        Dabei mach ich doch kein Update, sondern ein Insert.

        MySQL-Version ist  5.1.33-community aus dem XAMPP.

        Liebe Grüße aus dem schönen Oberharz

        Tom vom Berg

        --
         ☻_
        /▌
        / \ Nur selber lernen macht schlau
        http://bergpost.annerschbarrich.de
        1. Hello,

          However, you cannot insert into a table and select from the same table in a subquery.

          Das habe ich eben wohl doch in der ersten Euphorie nicht richtig ingterpretiert.
          Es geht also nicht, dies in einem Statement abzuwickeln.

          Folglich muss die Tabelle gesperrt werden für das select sum() und das anschließende Insert.

          Liebe Grüße aus dem schönen Oberharz

          Tom vom Berg

          --
           ☻_
          /▌
          / \ Nur selber lernen macht schlau
          http://bergpost.annerschbarrich.de
        2. Hi!

          The target table of the INSERT statement may appear in the FROM clause of the SELECT part of the query. (This was not possible in some older versions of MySQL.) However, you cannot insert into a table and select from the same table in a subquery.
          Ich bekomme aber trotzdem immer diese Fehlermelgung:
          ERROR 1093 (HY000): You can't specify target table 'zahl' for update in FROM clause

          Bei welchem Statement genau? Beachte den Unterschied zwischen INSERT ... SELECT und einen INSERT mit SELECT in einem Subquery.

          Lo!

          1. Hello,

            Bei welchem Statement genau? Beachte den Unterschied zwischen INSERT ... SELECT und einen INSERT mit SELECT in einem Subquery.

            Ich hatte versehentlich Klammern gesetzt hinter dem Select...

            insert into buchung (id_user, betrag)
            select 3, sum(betrag) from buchung
            where id_user = 3;

            So geht es. Und dann ist auch keine Sperre mehr notwendig.

            Und wenn man den vorhandenen Betrag ausbuchen will, dann eben ein Minus für sum(betrag).

            Liebe Grüße aus dem schönen Oberharz

            Tom vom Berg

            --
             ☻_
            /▌
            / \ Nur selber lernen macht schlau
            http://bergpost.annerschbarrich.de