PHP Online-Game -> HP Regenerieren

iGDark

Lt. Junior Grade
Registriert
Sep. 2005
Beiträge
306
Moin,

derzeit bastle ich an einem Online-Game. Die Sachen laufen alle soweit ganz gut...nur bei einer Sache bin ich am rätseln.
Man kämpft gegen Monster / Arena....dabei verliert man logischer weise Healthpoints (im folgenden HP).
Diese HP müssen logischer weise wieder aufgefüllt werden (über die regenerations-rate bestimmt).
Das ganze beim User darzustellen soll nicht das Problem sein, er sieht seinen HP balken nur durch javascript ansteigen und fertig, der reale wert steht in der datenbank.
ich möchte
a) aus sicherheitsgründen
b) aus logischen gründen (hp müssen weiter ansteigen, auch wenn der user sich ausloggt)

nicht das die HP beim User über AJAX o.ä. aktualisiert werden. nun stelle ich mir natürlich die frage wie ich das anstelle da schließlich die HP-Regeneration durch die Regenerationsrate bestimmt wird.
Habe mit dem gedanken gespielt einen Cronjob einzurichten. Der müsste aber im sekunden oder zweisekunden-takt laufen um die HP wirklich auf dem aktuellen stand zu halten. (weiß gar nicht ob es möglich ist es im sekunden takt zu machen?!?!)
zusätzlich würde meine Datenbank dadurch ziemlich belastet werden und die hat an und für sich durch die ganzen equips, quests etc. schon recht gut zu tun wenn das ding mal klappt (man will ja die hoffnung nicht aufgeben das leute das spiel spielen xD)

es ist eben mein erstes browsergame und daher habe ich da noch nicht so viel erfahrung. vielleicht kann mir ja jemand einen lösungsansatz veraten :)
denken + googlen kann ich selber, brauch nur nen ansatz wie ich dieses problem lösen kann ohne das ich ne datenbank-abfrage im sekundentakt laufen lasse :D

danke schonmal :)
 
Auf einem normalen Webspace ist das kaum sinnvoll hinzubekommen. Du müsstest in dem Fall wohl einen vserver mieten und dann ein entsprechendes Programm laufen lassen (C, Java oder auch CLI-PHP). Ein Vorteil einer solchen Lösung könnte auch sein, dass du bei einer gut geplanten Architektur eben nicht dauernd die Datenbank pollen musst sondern man die Daten aus dem RAM holen kann und nur von Zeit zu Zeit in die DB speichert damit bei einem Absturz/Stormausfall nicht alles weg ist. memcached könnte man da z.B. einsetzen. Das bietet auch eine Integration in PHP an.
Allerdings musst du dich dann mit der Administration und Einrichtung eines Servers auskennen...
 
hi,
danke schonmal für die antwort :)
einen vserver habe ich schon lange (hosteurope) :P
der ist auch eingerichtet und würde für das game zu testzwecken eben ne subdomain bekommen. server ist also überhaupt nicht das problem :D

dann werd ich mich jetzt mal in die tiefen von goolge stürzen *memcached in die suche eingebe*


(auf dem server läuft linux (ubuntu)....und das benutzte ich daheim auch...servereinrichtungssachen sind nicht so das problem wie die hp-problematik :D)
 
Zuletzt bearbeitet:
Man könnte doch folgendes machen:
Bei jedem Aufruf wird ein Zeitstempel hinterlegt.
Und wenn der User sich ausloggt und am nächsten Tag wieder einloggt,
dann wird berechnet, wie viel Zeit vergangen ist und entsprechend die HP-Zahl erhöht.

Edit: Dadurch spart man sich die permanenten Aktualisierungen.
 
Zuletzt bearbeitet:
hi,

das ist mir auch schon eingefallen. hat aber dann natürlich den nachteil das der user z.b. nicht angegriffen werden kann während er nicht online ist bzw. das sein profile einfach nicht die reale HP zahl enthält.
hab mir gerade mal so paar sachen zu memcached angeschaut und denke das damit eine gute, schnelle und effiziente lösung geschaffen werden kann :)

zudem das das hp auffüllen eh keinen tag dauert sondern je nach reg-rate und hp-stand viell. 5 minuten oder so ^^
 
Doch er kann angegriffen werden. Das ist ja das schöne daran.
Wenn jemand einen User angreifen möchte, dann werden vorher dem seine Daten aktualisiert.
Weil ob die Aktualisierung vom User selbst oder von jemand anderen aufgerufen wird, ist doch völlig egal.
Mit einer Zeit gesteuerten Funktion wäre das genau das selbe, genauso als ob ein anderer User es machen würde, nur dass sie wesentlich rechenintensiver ist.
 
hmm...
du meinst das jetzt praktisch so.

User hat volle HP -> Greift an, -200 HP, Rest-HP = 130 -> Unix-Timestamp mit 130 HP

dann kommt ein profil-besucher oder der spieler aktualisiert selber seine daten dann kommt

unix-timestamp von jetzt - timestamp der db = zeit zwischen letzter aktualisierung.

130 HP + (HP-reg-rate * zeit zw. aktualisierung)
-> db update der hp + neuer timestamp
 
Genau so ist es.

Und auf der Browserseite kann per Java-Script ja trotzdem in Echtzeit berechnet werden.
So bekommt der User alles in Echtzeit präsentiert und der Server hat nur was zu tun, wenn jemand sein Profil aktualisiert.
 
eigentlich auch gut.

ja der user bekommts eh in echtzeit aktualisiert. nur das das javascript ja auf seinem client rennt und nicht aufm server :D

ich probiers mal aus :)
danke :D
 
Solche Ansätze wecken bei mir immer Gedanken an Probleme hinsichtlich der Threadsicherheit.
Beispiel: Ein Spieler würde gerade durch einen Kampf HP verlieren aber ein anderer aktualisiert im selben Moment weil er das Profil besucht. Nun KANN (nicht: muss) es sein, dass der Spieler gar keine Punkte verliert weil der Profilbesuch das Ergebnis des Kampfes praktisch überschreibt.
Daher muss das alles sehr genau durchdacht sein! Das Problem ist bei solchen Sachen dann auch, dass sie schwer nachvollziehbar sind und bei wenig Last auch praktisch nicht auffallen. Je stärker frequentiert der Server aber wird, umso öfter treten solche Phänomene dann auf und der Entwickler kann es sich erst nicht erklären weils bei seinen Test ja nicht aufgetreten ist.
 
Sollte nicht passieren weil:
Spieler startet Kampf -> HP werden aus der DB geholt
der kampf wird in hunderstel sekunden durch php ausgeführt, die darstellung erfolgt wieder durch javascript, was bedeutet das die hp zum zeitpunkt der darstellung des kampfes schon längst aktualisiert sind und keinen einfluss mehr haben.
php script rennt den kampf durch -> spieler verliert hp -> hp stand wird sofort nach dem kampf in die db geschrieben.
um den effekt den du gerade meinst zu erreichen muss eine anfrage an den server praktisch zeitgleich erfolgen was eig. nicht vorkommen sollte. zumindest kann man das nicht gezielt erreichen, schon alleine die WAN-Verbindung lässt das nicht zu. es würde ein großer zufall sein denk ich
 
Zuletzt bearbeitet:
Ich spreche auch nicht unbedingt davon, dass ein Spieler quasi gleichzeitig was schickt (was natürlich auch ein Angriffsszenario auf das Spiel ist und im Prinzip sogar relativ problemlos für den Angreifer durchführbar ist!). Es können aber auch durchaus andere Spieler gerade im selben Moment zufällig die Aktualisierung des gerade kämpfenden Spielers auslösen.

Die Problematik einfach damit wegzuwischen, dass es unwahrscheinlich ist, ist keine gute Programmierpraxis und zeigt wohl, dass du entweder das Projekt kaum ernst nimmst oder kaum Erfahrung hast. In der Praxis werden solche Nebenläufigkeitsprobleme nämlich durchaus oft auftreten - zumindest wenn das Spiel wirklich erfolgreich sein soll und tatsächlich mehrere Personen gleichzeitig spielen.

Im Übrigen sollte das genannte Szenario nur ein Beispiel sein, das mir auf die Schnelle aufgefallen ist. Ähnliche Effekte können auch in anderen Bereichen auftreten.
 
Ich verstehe die Bedenken dabei.

Aber die Frage ist, wie man es sonst machen sollte?
Man könnte natürlich die Datenmanipulation während längeren Berechnungsphasen über eine Variable verbieten, aber ist das die Lösung?

Ich weiß leider nicht wie PHP programmiert ist, aber ich denke mal das da schon irgendwie an solche Fälle gedacht wurde, oder? (Da es ja eine Problematik der Sprache wäre)
Am einfachsten wäre es, wenn es in PHP einen Threat geben würde, der jede Anfrage nacheinander abarbeiten würde. Dann würde das Problem nicht auftreten.
Aber ich weiß nicht, wie PHP dahingehend umgesetzt wurde.
 
Wohl eher die Erfahrung :D wie ich schon sagte ist es das erste game das ich schreibe und es ist nunmal das erste mal das ich mich so einer problematik stellen muss.
noch ist bezüglich der hp nichts programmiert da ich noch am kampfszenario arbeite. ohne das passiert eh nix mit den hp zahlen. *über eine formel grübel wie ich die treffsicherheit relativ zur geschicklichkeit und der stärke setzte, aber immer eine wahrscheinlichkeit da sein muss nicht zu treffen*

bei deiner möglichkeit (memcached) ist es so gemeint das sämtliche HP-Zahlen (von allen spielern, ob online oder offline) im arbeitsspeicher stehen und meinetwegen alle 5 minuten die DB vollkommen aktualisiert wird, oder?
ich habe mir ein paar sachen durch gelesen zu diesem thema. ich weiß aber irgendwie noch nicht wie ich den server die hp jedes einzelnen spieler ausrechnen lasse. aber da werd ich noch mehr lesen müssen bevor ich soweit bin, und bevor ich das mache möchte ich doch erstmal ein mini-kampf-szenario programmiert haben :)
 
In einem normalen Apache ist PHP meist so konfiguriert, dass bei jedem Request ein neuer Apache-Prozess geforkt wird. In dem läuft dann das PHP-Script ab. Somit sind zwei parallel laufende PHP-Skripte vollkommen unabhängig voneiander und wissen gar nichts von ihrer gegenseitigen Existenz.

bei deiner möglichkeit (memcached) ist es so gemeint das sämtliche HP-Zahlen (von allen spielern, ob online oder offline) im arbeitsspeicher stehen und meinetwegen alle 5 minuten die DB vollkommen aktualisiert wird, oder?
Jop.

Am Besten wäre ein zentraler "Gameserver", der alle "schreibenden" Requests annimmt und auswertet (Requests, die nur lesen können auch direkt aus der Datenbank oder dem memcache lesen). Mit C++ oder Java kann man das sehr gut handlen. Dies unterstützen ja auch mehrere Threads, so dass z.B. ein Thread alles in eine Queue schickt und der Hauptthread diese Queue dann abarbeitet. Kampfberechnungen sind zudem in solchen Sprachen wohl auch performanter als in PHP (selbst wenn man xcache oder ähnliches verwendet ist PHP noch langsamer). Damit ist die Problematik der Nebenläufigkeit praktisch vollständig behebbar. Durch die in Hochsprachen vorhandenen Synchronisierungsmethoden kann man später auch mehrere Hauptthreads laufen lassen wenn man einen Dual-Core oder Ähnliches hat.
 
Ich hab mir nur kurz den thread durchgelesen, und bin mir nichtmal sicher ob ich alles verstanden hab;)

Die HP regenerations rate liegt ja fest...
Wenn also die HP anzahl abgefragt wird, dann kannst du diese ja leicht bereichen, in dem du rechnest:
letzer_abgefragter_hp_wert + regenrations_rate * zeit

das ganze kannst du natürlich nicht in Echtzeit im browser anzeigen, aber die Lösung ist hier schätzen:
Du lässt die hp per javascript einfach mit der gleichen regeneratiosn_rate steigen.. Im normallfall ist das genau der wert, der mit der berechnung übereinstimmen würde. Ein beschiss ist hier somit nicht möglich.

und wenn du regelmäßig ohne ein neuladen der seite neue informationen haben möchtest, dann kommst du nicht drum herum eine regelmäßige ajax abfrage zu machen... aber das dann nur relativ selten.. das hängt natürlich stark vom konzept des spiels ab.
Ein browser spiel ist in jedem falle rundenbasiert... und wenns nur eine sekunde ist, sind es dann doch irgendwo runden (sprich: diskret)


edit:
Beispiel: Ein Spieler würde gerade durch einen Kampf HP verlieren aber ein anderer aktualisiert im selben Moment weil er das Profil besucht. Nun KANN (nicht: muss) es sein, dass der Spieler gar keine Punkte verliert weil der Profilbesuch das Ergebnis des Kampfes praktisch überschreibt.
das nennt man race condition.
da die hp und sonst auch alle informationen in einer datenbank gespeichert werden, dann packst du einfach alles was diese informationen verändert in eine datenbank transaktion, womit diese atomar wird. (d.h. zwischen allen sql anweisungen in der transaktion passiert (logisch gesehn) auf der datenbank nichts anderes)

es ist also nicht möglich
spieler 1: hp auslesen
spieler 2: hp auslesen
spieler 1: hp updaten (-100);
spieler 2: hp updaten (+200)
energebnis: +200



Spieler startet Kampf -> HP werden aus der DB geholt
der kampf wird in hunderstel sekunden durch php ausgeführt, die darstellung erfolgt wieder durch javascript, was bedeutet das die hp zum zeitpunkt der darstellung des kampfes schon längst aktualisiert sind und keinen einfluss mehr haben.
Bitte vergiss diesen Gedankengang aber GANZ schnell wieder.
Oder merk ihn dir sehr gut und sehr lange als ein beispiel "how NOT to do it"
denk garnicht daran nochmal an so etwas zu denken. (..?lol)


Ich weiß leider nicht wie PHP programmiert ist, aber ich denke mal das da schon irgendwie an solche Fälle gedacht wurde, oder? (Da es ja eine Problematik der Sprache wäre)
Am einfachsten wäre es, wenn es in PHP einen Threat geben würde, der jede Anfrage nacheinander abarbeiten würde. Dann würde das Problem nicht auftreten.
Aber ich weiß nicht, wie PHP dahingehend umgesetzt wurde.

Das wär ja lustig, wenn ein php script einzig und allein auf einem server laufen dürfte ohne dass ein anderes script laufen darf.. sprich ein thread hat die alleinige Macht über die CPU so lange er läuft.. und wenn es ein thread ist der lange läuft, dann kann der webserver halt zu der zeit nix anderes machen.. auch alle anderen Prozessoren werden so lange still gelegt.
PHP wäre wohl verdammt langsam, wenn das der Fall wäre.

Nene das ist schon dein Problem, und das musst du auch selbst lösen. Kritische Bereiche als solche markieren. Lies dir mal ein wenig etwas über semaphore durch. Das ist allerdings nur das Konzept dahinter.. Bei php wird das glaub ich etwas schwer, da ein php script das gerade abgearbeitet wird kein anderes php script kennt. Die Lösung liegt hier denke ich bei einer Datenbank Transaktion.



Am Besten wäre ein zentraler "Gameserver", der alle "schreibenden" Requests annimmt und auswertet (Requests, die nur lesen können auch direkt aus der Datenbank oder dem memcache lesen). Mit C++ oder Java kann man das sehr gut handlen. Dies unterstützen ja auch mehrere Threads, so dass z.B. ein Thread alles in eine Queue schickt und der Hauptthread diese Queue dann abarbeitet. Kampfberechnungen sind zudem in solchen Sprachen wohl auch performanter als in PHP (selbst wenn man xcache oder ähnliches verwendet ist PHP noch langsamer). Damit ist die Problematik der Nebenläufigkeit praktisch vollständig behebbar. Durch die in Hochsprachen vorhandenen Synchronisierungsmethoden kann man später auch mehrere Hauptthreads laufen lassen wenn man einen Dual-Core oder Ähnliches hat.
Wenn man mit java arbeitet hat man das Problem nicht, dass sich zwei threads nicht gegenseitig kennen, und man kann im gegensatz zu php vieles einfach im Ram halten. (php benutzt natürlich auch RAM, aber man hat über einen aufruf auf eine php seite keinen weiteren zugriff auf den RAM)

Aber da ich java nicht mag, find ich es mit php toller.. wobei ich deutlich mehr über das spiel konzept wissen müsste, um sagen zu können, dass das ganze noch sinnvoll mit php schaffbar ist. Es gibt sicher ein paar sachen, wo Java die DEUTLICh bessere wahl wäre, aber ich denke in den meisten fällen ist PHP die bessere lösung - insbesondere dann, wenn man das Web so benutzen möchte, wie es gedacht ist, und man sich bei einem spiel auch so füheln soll, dass man sich noch im web befindet..
 
Zuletzt bearbeitet:
Mir gefällt die Lösung ganz gut ein Programm zu machen, welches die Änderungen durchführt. Das Spiel-Script schreibt also da rein was geändert werden soll und das andere Programm führt diese Änderungen nacheinander aus, so könnte nichts verloren gehen. Wurde aber im Prinzip schon so gesagt.
 
Es gibt sicher ein paar sachen, wo Java die DEUTLICh bessere wahl wäre, aber ich denke in den meisten fällen ist PHP die bessere lösung - insbesondere dann, wenn man das Web so benutzen möchte, wie es gedacht ist, und man sich bei einem spiel auch so füheln soll, dass man sich noch im web befindet.
Moment! Ich sprach nicht von einem Java-Applet, das beim Benutzer läuft! Es geht nur um das Backend und das ist wenig relevant für den Nutzer weil er es in der Regel nicht sehen wird!
 
ich glaube ich sollte hier noch zusätzlich erwähnen das ich php mit objektorientierung (und der dazugehörigen datenkapselung) verwende.
d.h. der spieler loggt sich ein, der hp wert von ihm wird einmal abgefragt und den rest behält er durch die session. nur wenn kampf-scripts abgerufen werden (und diese müssen vollzogen werden) können die hp überhaupt geändert werden. und bevor man kämpft werden sie nocheinmal aus der db geholt damit im objekt nichts falsches sein kann.
nochmal: hp werden aus db geholt, kampf durchgerechnet, objekt des spielers aktualisiert (wieviel hp er noch hat etc.) und in die datenbank zurück geschrieben. der spieler greift prinzipiell nur auf die DB zu wenn er kämpfe oder sonderaktionen (wie skillen) anfordert, ansonsten arbeitet er schön auf seinem spieler objekt und kann somit die datenbank nicht manipulieren. ich denke get und set der objekt-klassen sollte ja ein begriff sein :D

@pw-toxic: wenn ich den gedanken vergessen soll dann begründe es mir doch bitte wenigstens :D

es ist aber echt verrückt (vor allem zwecks bug using etc.) das man die hp-regeneration vom client vollziehen lässt. und aus dem oben genannten grund das die hp weiter regeneriert werden sollen wenn man offline ist mal ganz zu schweigen :)

hier muss der server eingreifen, nur wie ist eine ganz andere frage :D
 
BerniG schrieb:
Moment! Ich sprach nicht von einem Java-Applet, das beim Benutzer läuft! Es geht nur um das Backend und das ist wenig relevant für den Nutzer weil er es in der Regel nicht sehen wird!
Ich rede auch von einem Java backend ;) java applets sind hässlich ;)

@pw-toxic: wenn ich den gedanken vergessen soll dann begründe es mir doch bitte wenigstens
Tut mir leid, aber Begründungen wurden hier schon zu hauf gegeben, warum das schlecht ist ;)

hier muss der server eingreifen, nur wie ist eine ganz andere frage
Ich dachte ich hab doch bereits erwähnt, wie der server das aktualisiert ;)
Die hp wird nur neu berechnet, wenn es dazu nötig ist. Man kann wohl davon ausgehehn, dass die HP Regeneration einem mathematischen Modell folgt. Somit brauchst du nichts "aktualisieren" wenn die hp nicht abgefragt wird. Wenn sie aber abgefragt wird, dann berechnest du den hp wert nach deinem mathematischen modell, und gut is...
Aber das sagte ich ja eigentlich bereits ;)
 
Zurück
Oben