JeuWeb - Crée ton jeu par navigateur
Comment faire pour qu'un combat se déroule à un timestamp donné ? - Version imprimable

+- JeuWeb - Crée ton jeu par navigateur (https://jeuweb.org)
+-- Forum : Discussions, Aide, Ressources... (https://jeuweb.org/forumdisplay.php?fid=38)
+--- Forum : Programmation, infrastructure (https://jeuweb.org/forumdisplay.php?fid=51)
+--- Sujet : Comment faire pour qu'un combat se déroule à un timestamp donné ? (/showthread.php?tid=6992)

Pages : 1 2


Comment faire pour qu'un combat se déroule au timestamp enregistré en base de donnée - yceos - 02-07-2013

Salut,

La solution est simple: declencher l'execution du script au moment ou le combat a lieu. Que se soit par un evenement one shot quelconque (par exemple un cron "temporaire") ou un polleur (un cron qui va regarder tous les X unites de temps s'il y a un truc a faire (unite a definir en fonction de la precision que tu veux)).

Je me suis retrouve face au meme probleme que toi il y a peu.

J'ai teste un peu le cron, mais pour moi ca se "rapproche" trop du systeme (le php a mon sens ne doit pas intervenir sur le systeme dans le cadre d'une application web comme ca).

J'ai teste avec du NodeJS (champion de la gestion de la concurrence du moment) ou mon Node servait de poller et interrogeait la BDD toutes les 5 secondes (puis toutes les secondes pour voir) pour savoir s'il y avait quelque chose a faire et le cas echeant le faisait. Mais j'aime pas le principe de "Je tourne en permanence pour rien".

J'ai choisi de tout mettre dans MySQL (qui dispose d'un event scheduler). Je declenche donc l'execution d'une procedure stockee a l'exact moment du timestamp. L'inconvenient c'est qu'il n'y a pas de moyen simple et secure d'executer autre chose que du SQL (il existe un petit module qui permet de faire des appels externes mais c'est pas secure, et un petit module qui permet de faire du Curl like mais c'est pas simple !) du coup il a fallut tout (re)ecrire en SQL plutot que PHP ... Y compris les mises a jours diverses et variees. L'avantage, tu as toutes les donnees sous la main vu que ta BDD est censee etre garante de celles-ci et c'est decorrele du PHP donc pas de temps d'attente du joueur. Comme tu declenche le tout au moment du timestamp, normalement tu as une vision instantanee valide de l'etat de tout (resources, flottes en vol, constructions en cours...).

C'est en tout cas la solution qui se rapproche le plus du temps reel que j'ai trouve ET qui m'a plu.

/!\ Attention, cette solution requiere d'avoir beaucoup de controle sur ton serveur, au moins un VPS serai donc necessaire.

Alternativement, tu pourrais mixer nos differentes propositions:
A l'instant indique par le timestamp faire une sorte de snapshot des donnees dont tu as besoin, puis les traiter en asynchrone a la prochaine action utilisateur. C'est un poil moins "temps reel" mais tu peux toujours travailler sur des donnees exactes. Ca devrait simplifier les procedures SQL si celles-ci te font peur !


Comment faire pour qu'un combat se déroule au timestamp enregistré en base de donnée - Xenos - 02-07-2013

Si t'as journalisé les évènements, c'est réglé. Normalement, dans ta BDD, tu aurais des lignes du type "Id joueur / Date de l'ordre / Armée concernée / Ordre", et donc, si tu as un ordre de mouvement pour cette armée avant le timestamp, sans ordre d'arrêt et sans que la distance entre le point de départ et le point d'arrivée n'ai été couverte, alors l'armée est encore en mouvement.
Ca rejoint peut-etre la réponse précédente, mais TL;DR et j'suis à la bourre pour mon taff...


Comment faire pour qu'un combat se déroule au timestamp enregistré en base de donnée - Aleskweb - 02-07-2013

A mon avis, pas besoin de faire du temps reel.

Si aucun joueur ne fais d'action, que le combat ait lieu ou pas ne change rien.

Donc faire un listing des actions programmées dans la BDD, faire un script de vérification et l’exécuter a chaque action d'un joueur. Il suffira de vérifier si le timestamp actuel a dépassé le timestamp de l'action.
Si il y a des actions qui auraient du se passer, les traiter, puis supprimer les champs traités de la BDD


fuuuuuuuuuuuuuuuuuuuuuuuuuuuck - niahoo - 02-07-2013

Et si deux joueurs chargent une page en même temps ?


Comment faire pour qu'un combat se déroule au timestamp enregistré en base de donnée - Aleskweb - 02-07-2013

Il y aura forcément un script php qui passera avant l'autre donc le deuxième ne traitera rien étant donné que celui de devant aura supprimé les champs


Comment faire pour qu'un combat se déroule au timestamp enregistré en base de donnée - Xenos - 02-07-2013

Nan, les script PHP pourraient, avec une faible probabilité, être concurrents (il suffit que l'interpréteur soit multi-thread ou multi-processus). Cela se voit très bien en exécutant un code comme ceci (pseudo-code, la source PHP est chez moi, pas au taff):

Code :
[b]Page.php:[/b]
for $n=1 to 128 {
echo('<img src=\"page2.php?time=".time()."&n=".$n."\"/>');
}

[b]Page2.php[/b]
sleep(10); // wait 10 seconds
header('content-type:image/png');
imagepng(imagecreatefrompng('my-png-file.png'));

L'idée est de faire une page qui va afficher 128 balises images, chacune avec une URL différente. Le navigateur va alors faire 128 requêtes (ou moins, suivant la limite fixée), et ces requêtes seront en parallèle: on recevra les images par "paquets" (généralement, par 2 ou par 6 à cause de la limite du nombre de connexion / domaine).
Donc, cela tend à prouver que les 6 scripts PHP sont interprétés en même temps, en parallèle.

En revanche, le SQL (s'il est bien foutu), sera le goulot d'étranglement, et c'est lui qui exécutera les requêtes l'une après l'autre.
Mais il ne faut pas compter sur PHP pour être "séquentiel"...

Donc, un script PHP du genre:
Code PHP :
$x mysql_query("SELECT `date` FROM `table` WHERE `id`=3");
mysql_query("UPDATE `table` SET `date`=($x+1) WHERE `id`=3"); 
Pourrait créer quelques soucis...
Deux scripts PHP parallèles faisant alors, avec `date` qui vaut 0 au début:

Code PHP :
PHP1$x mysql_query("SELECT `date` FROM `table` WHERE `id`=3");
PHP2$x mysql_query("SELECT `date` FROM `table` WHERE `id`=3");
PHP1mysql_query("UPDATE `table` SET `date`=($x+1) WHERE `id`=3");
PHP2mysql_query("UPDATE `table` SET `date`=($x+1) WHERE `id`=3"); 

Et en sortie, on a `date` qui vaut 1 en sortie, et pas 2, car la valeur $x de PHP2 a écrasée celle qui PHP1 avait sauvée...



ET b*** changez ces noms de sujet qui empêchent d'utiliser les réponses rapides !


féééchiéééé - niahoo - 02-07-2013

Voilà, merci Argorate (et Xenos) pour démontrer que dans les mains de quelqu'un qui connait les choses seulement à-peu-près le calcul de l'état global par un seul joueur est une mauvaise chose. Donc comme le dit Xenos tu peux très bien avoir des requêtes SQL croisées (notamment sur des mutus ou des VPS ou le proc est partagé) si tu fais tes select / insert / update de façon séquentielle et non pas de façon atomique.


RE: Comment faire pour qu'un combat se déroule à un timestamp donné ? - hercull - 08-07-2013

Merci pour vos réponses j’avoue ne pas avoir tout compris cela est surement du à mon manque d’expérience, mais je retiens plusieurs idées intéressantes soit je trouve un moyen de déclencher une procédure stockées au moment exact du timestamp comme sa les infos sont a jour au bon moment comme la dit yceos, cela me plait bien mais je ne sais pas comment mettre en place cela une fois la procédure stockée créer.
Et la mis en place d'un cron qui effectue une action tt les x seconde ne répond vraiment à ce besoin.

Ou sinon comme la dit Aleskweb faire uniquement les actions quand le joueur intervient et vérifier si le timstamp et inférieur ou supérieur a celui stockée et effectuer l'action ou afficher un compte a rebours du temps restant.
Seulement dans le cas ou il y a 3 joueurs qui interviennent le joueur 1 attaque le joueur 3 dans 1h, le joueur 2 attaque le joueur 3 dans 1h10: seulement les actions ne se font que lorsqu’un joueur effectue une action, disons que le joueur 1 et 3 sont déconnecté et le jouer 2 est connecté pendant l'attaque donc on arrive a 1h la 1ere attaque il ne se passe rien car les 2 joueur concerné sont absent , et a 1h10 avant de calculer la seconde attaque on doit calculer la 1ere donc il faut faire les calcul d’après les infos d'il y a 10 minutes et donc le seul moyen est d'enregistrer les infos dont on aura besoins au moment du timstamp.
Question comment réalisé cela? est ce la meilleur méthode a utilisé, ou y en a t il une plus simple?
Merci de votre aide.


RE: Comment faire pour qu'un combat se déroule à un timestamp donné ? - Aleskweb - 14-07-2013

Comme l'a démontré xenos, ma solution a une faille. En effet si le script est appelle plusieurs fois au meme moment, il y a un risque qu'il s'exécute plusieurs fois et les actions seront donc traitées plus d'une fois.
Sur un petit jeu, la probabilité est presque nulle, sur un gros elle n'est plus négligeable.
Tu peux meme réduire se risque en faisant la requete pour recevoir la liste d'actions a executer puis de les supprimer juste apres.
Aussi, meme si les requetes sql sont croisées, elles ne peuvent pas être simultanées, pourquoi ne pas faire cette instruction select/delete en passant par une multi query?

Sinon pour ta question, vu que tu as les timestamp des actions, il te suffit de les traiter dans l'ordre ( timestamp croissant) et a chaque action traitee, la mettre a jour dans la base de donee, ainsi l'action suivante sur ce meme joueur pourras obtenir les infos sur ce dernier tel qu'il aurait été a ce timestamp la dans la bdd. (Pas évident a expliquer)