Reporter l'exécution d'un fichier PHP
#1
Bonjour,

J'ai une petite question afin d'avoir votre avis sur comment faites-vous pour gérer (en programmation) l'achèvement des certaines tâches.

Nous avons tous un jeu où la construction du bâtiment se termine dans X, où l'attaque se déroulera dans Y, etc...

Personnellement, sur mon jeu, j'insert ces données dans une table où je vérifie via mes pages s'il telle action s'est terminée, si c'est le cas, on exécute la fonction permettant d'effectuer ladite tâche (construction bâtiments, lancement d'une attaque, etc.); mais ce qui s'avère peut optimum dans la mesure où si j'ai mon bâtiment qui se termine à 3h59 et si personne ne se connecte avant 7h00 du matin bah... L'achèvement du bâtiment ne sera pas effectif pas avant 7h00 du matin... (ce qui peut être problématique si c'est un bâtiment de production où on perdrait 3h00 de production...).

J'aimerais savoir si vous gérez ça différemment ? Si oui, comment ?

Par exemple, sur debian, nous avons la possibilité d'exécuter une commande plus tard, grâce notamment avec la commande "at" . Connaîtriez-vous un moyen similaire de faire pareille ? (via PHP)

Ce qui reviendrai à dire :
Lorsque je lance la construction d'un bâtiment (ou une attaque, ou autre), je dis à PHP lance-moi le fichier fichier.php à 13h53

Merci,
Répondre
#2
Réponse rapide : Suffit de faire les calculs des heures "perdues" à la connexion de l'utilisateur. Idem si c'est une attaque ou autre. Pas besoin de lancer un script à un temps x ou autre.

Réponse complète : Je laisse le soin aux autres de le faire. Xenos par exemple :relieved:
Répondre
#3
Salut,

ouep, j'avais déjà abordé le sujet là: https://toile.reinom.com/non-aux-taches-...aque-datee

Dans l'idée, c'est bien ce que tu as déjà en place: le batiment est censé se terminer à 3H59, mais le calcul a lieu à 7h du matin. Le calcul va donc se charger de simuler la construction du batiment à 3h59 et de simuler l'écoulement des 3h01 qui ont suivies. Il stockera alors la date de dernière production du batiment en BDD, ainsi que la quantité déjà produite à cette date (les stocks cette date donc).

Après, rien n'interdis d'avoir un CRON horaire ou quotidien pour éviter de trop "stacker" des actions, surtout pendant la nuit (aka, le jour, tu as peut-être des joueurs en continue qui joue, donc des simulations assez rapprochées et courtes, mais si personne ne vient de 22h à 8h, alors il va y avoir 10h de simulation à lancer lors de la visite du 1er joueur du jour: un CRON horaire permet de restreindre cette charge à 1H max).

Mais l'important, c'est bien et bien de détacher le moment où l'action a lieu dans le jeu (fin de construction du batiment) et le moment où cette action est réellement calculée. Parce qu'au fond, osef complètement de simuler la construction du batiment à 3h59 pile poil (ce qu'on n'arrivera *jamais* à faire d'ailleurs): si personne n'est là pour voir l'effet de ce bâtiment, il peut être construit ou démoli, ça ne charge rien : ) (oui, les jeux web sont quantiques: c'est un batiment de Schrodinger, dans un été superposé construit/non-construit)

Et pour répondre à l'autre question, je n'ai pas connaissance d'un "at" en PHP. Après, rien ne t'interdis d'avoir un script PHP lancé en ligne de commande, qui tourne en boucle (while true + usleep 10) et qui se charge de faire des calculs à une heure donnée. Mais à mon avis, c'est une architecture moisie.
Répondre
#4
Il y a plusieurs possibilités selon le besoin derrière :

1) Ton utilisateur est isolé et sans interaction avec d'autres joueurs lorsqu'il est absent : tu peux te contenter de calculer les manques et différences à son retour en stockant les données qui vont bien

2) Ton utilisateur évolue dans un environnement en interaction avec d'autres joueurs : tu ne peux pas, comme dit par les précédentes réponses, te contenter de recalculer ça au retour du joueur concerné. En tous les cas, tes actions en interaction avec d'autres seront stockées dans une espèce de pile (une simple table des actions en somme) que tu iras lire et traiter dans l'ordre chronologique, de façon à respecter la temporalité des actions des utilisateurs.
Dès lors, dans ce cas précis, tu as deux situations selon la temporalité nécessaire :
a. Un traitement toutes les minutes au plus fin : la tâche cron suffira, c'est là son minimum
b. Un traitement plus bas que la minute voire en temps réel : la proposition de Xenos qui est une alliance entre plusieurs solutions pour garder toujours à jour les données en question car il n'existe rien de très propre permettant dans une technologie assez basique de faire de tels traitements.

Toutefois, moyennant son propre serveur, ça me paraît pas impossible de configurer des traitements automatiques continus, au risque évidemment de le crasher si on ne sait pas faire. Mais là ça dépasse mes connaissances.
Répondre
#5
Que ce soit à la minute ou en dessous, ton archi pue des genoux (pour ne pas dire d'ailleurs) si t'en viens à ce genre de solution qui boucle. Là, soit tu revois ton process/gameplay/façon de faire, soit tu fais comme un jeu AAA, avec un "démon" (serveur) tournant en continue pour gérer le temps réel. Mais je connais pas de FPS ou assimilé qui se joue en ligne en temps réel avec une BDD...

De toute façon, c'est assez simple: quand une archi bien puante comme ça est utilisée, elle ne fait rien 99.9% du temps, et ne fais quelque chose "d'utile" que 0.1% de ce temps. Donc, t'as multiplié tes coûts et tes risques de bug par 1000, pour rien. En revanche, ce genre de chose marche sur un jeu AAA (exemple le plus classique de jeu multi en temps réel) car là, le serveur ne se tourne pas les pouces 99.9% du temps: il est chargé tout le temps de la partie (qui parfois, est "tournante", aka en fin de partie, le serveur passe à la map suivante et on recommence, pas toujours avec les mêmes joueurs puisqu'ils vont et viennent, mais avec la même charge pour le serveur).

En revanche, ta solution est bonne Metallique: tu sauves en BDD le fait que le batiment sera fini à 3H59, puis quand un joueur se pointe (ou que le cron anti-stack-trop-grosse tourne) à 7h, tu marque le batiment comme construit et tu produis les ressources correspondant à la différence de temps (3H01 de production). Tu marques alors que le batiment a produit pour la dernière fois à 7H, et quand le joueur se repointe à 8H, tu procède de même: tu as 1 batiment qui a produit à 7H pour la dernière fois, il est 8H, donc le batiment a produit 1H, et tu ajoutes ces ressources aux stocks du joueur, puis tu marque le batiment comme ayant produit à 8H.
Et si un autre joueur attaque à 10H et pille tous les stocks du premier, alors tu procèdes selon le même schéma: le batiment du 1er joueur a produit à 8H pour la dernière fois, donc, tu calcules les ressources produites pendant ces 2H, tu les ajoutes aux stocks du 1er joueur, tu marque que le batiment a produit pour la dernière fois à 10H, et tu transfère toutes les ressources du 1er joueur vers le 2nd joueur pour simuler l'attaque.

C'est simple, efficace, et adapté à une archi web classique.
Répondre
#6
Salut,

Désolé pour ma réponse tardive!

Dommage, j'aurais préféré qu'un truc genre "at" puisse exister. Pas grave, je vais m'adapter et me pousser à améliorer mon architecture notamment sur certaines tables afin d'optimiser le tout et éviter d'attendre qu'un joueur se connecte afin de procéder à toutes les mises à jour (et éviter au maximum l'utilisation de tâches crons).

Merci!
Répondre
#7
(02-08-2019, 09:47 PM)Xenos a écrit : Que ce soit à la minute ou en dessous, ton archi pue des genoux (pour ne pas dire d'ailleurs) si t'en viens à ce genre de solution qui boucle. Là, soit tu revois ton process/gameplay/façon de faire, soit tu fais comme un jeu AAA, avec un "démon" (serveur) tournant en continue pour gérer le temps réel. Mais je connais pas de FPS ou assimilé qui se joue en ligne en temps réel avec une BDD...

De toute façon, c'est assez simple: quand une archi bien puante comme ça est utilisée, elle ne fait rien 99.9% du temps, et ne fais quelque chose "d'utile" que 0.1% de ce temps. Donc, t'as multiplié tes coûts et tes risques de bug par 1000, pour rien. En revanche, ce genre de chose marche sur un jeu AAA (exemple le plus classique de jeu multi en temps réel) car là, le serveur ne se tourne pas les pouces 99.9% du temps: il est chargé tout le temps de la partie (qui parfois, est "tournante", aka en fin de partie, le serveur passe à la map suivante et on recommence, pas toujours avec les mêmes joueurs puisqu'ils vont et viennent, mais avec la même charge pour le serveur).

En revanche, ta solution est bonne Metallique: tu sauves en BDD le fait que le batiment sera fini à 3H59, puis quand un joueur se pointe (ou que le cron anti-stack-trop-grosse tourne) à 7h, tu marque le batiment comme construit et tu produis les ressources correspondant à la différence de temps (3H01 de production). Tu marques alors que le batiment a produit pour la dernière fois à 7H, et quand le joueur se repointe à 8H, tu procède de même: tu as 1 batiment qui a produit à 7H pour la dernière fois, il est 8H, donc le batiment a produit 1H, et tu ajoutes ces ressources aux stocks du joueur, puis tu marque le batiment comme ayant produit à 8H.
Et si un autre joueur attaque à 10H et pille tous les stocks du premier, alors tu procèdes selon le même schéma: le batiment du 1er joueur a produit à 8H pour la dernière fois, donc, tu calcules les ressources produites pendant ces 2H, tu les ajoutes aux stocks du 1er joueur, tu marque que le batiment a produit pour la dernière fois à 10H, et tu transfère toutes les ressources du 1er joueur vers le 2nd joueur pour simuler l'attaque.

C'est simple, efficace, et adapté à une archi web classique.

Vu que le joueur est dans son coin, il peut le résoudre assez simplement. De même que tu peux t'en sortir si tes joueurs sont synchrones.

Tu t'y prendrais de la même façon si tes joueurs interagissent de façon asynchrone ? Je t'offre une situation : si A est absent et que B attaque A, B va détruire des éléments de A. C va ensuite attaquer A à la suite de B. Les données de A doivent être mises à jour à C. Le joueur A n'a jamais été là. Admettons qu'une fois l'attaque lancée les joueurs B et C se sont aussi absentés. Tu te retrouves, au moment précis de l'attaque, sans aucun joueur connecté.

Tu attends donc le retour d'un d'entre eux voire de tous pour mettre à jour les données ? Tu attends la cron qui tourne, par exemple toutes les minutes ? Et donc, si un joueur D attaque dans cette minute, il joue sur des données non à jour ? Mettre à jour les données quand le joueur se repointe dans une situation d'interaction n'est pas satisfaisant, de même que le cron ne suffit pas. Le cron peut gérer cette situation si tu fais une exécution dans l'ordre des événements, mais il ne gérera pas un joueur E qui viendrait espionner la situation vécue dans le laps de temps où ça n'a pas été exécuté. Le joueur E n'aura donc pas la vision du jeu à N+30s d'un événement arrivé à N parce que ton cron tourne à N+1m. Tu peux en revanche le gérer de façon insatisfaisante en renvoyant le résultat au joueur E à N+1min, une fois que son propre événement est exécuté.

Bien évidemment, ça correspond à des besoins de jeux web classiques (tu en as pas mal, c'est pas un souci, et avec une bdd) où ton langage serveur est bien souvent PHP. Faire des démons en PHP qui soient infinis, ça se fait, mais il faut faire gaffe si tu es sur une version antérieure à 5.3 (me semble) pour gérer les fuites mémoires potentielles.

Par contre, je ne vois pas en quoi le fait d'avoir une cron (qui reste à proprement parler un démon) qui tourne multiplierait ton risque de bug puisque c'est quelque chose de parfaitement géré par le serveur. Je vois bien pour un démon infini fait à la main, en revanche.

Et oui, un FPS ne serait pas géré ainsi, de même qu'une LAN classique où ta partie dure plusieurs minutes à plusieurs heures tout au plus et pour lequel tu peux te passer de bdd. Déjà, parce que le serveur peut être un joueur, et non pas ton propre serveur. Et, ma foi, il ne serait pas fait avec du PHP non plus comme pour la plupart des sites, ce que sont en général les jeux webs classiques. Parce que, oui, les besoins et dimensionnements ne sont pas les mêmes.
Répondre
#8
Tu te retrouves, au moment précis de l'attaque, sans aucun joueur connecté.
On s'en balec, le web n'est pas conçu initialement pour faire du temps réel, y'a pas de notion de "sans aucun joueur connecté" (ou dit autrement, il n'y a jamais de joueur "connecté": ce sont des échanges ponctuels serveur/client, pas des flux continus).
Quand le joueur D va se pointer, les attaques/productions/j'sais pas quoi des autres joueurs seront résolus (ou quand le cron horaire/quotidien tournera, qui n'est à visualiser que comme un "joueur" régulier qui repasse toutes les X heures, histoire de ne pas trop stacker de trucs)

Tu attends donc le retour d'un d'entre eux voire de tous pour mettre à jour les données ?
C'est ça. S'il n'y a personne pour "voir" le jeu, y'a pas besoin de se poser la question de "mais attends, les combats n'ont pas été résolus là?!"

Tu attends la cron qui tourne, par exemple toutes les minutes ?
Non, horaire ou quotidien. Y'a aucun intérêt à bousiller un serveur avec des cron à la minute

Et donc, si un joueur D attaque dans cette minute, il joue sur des données non à jour ?
Non, quand le joueur D se pointe sur une des pages du jeu pour faire son attaque ou voir ce qu'il se passe, on résout la stack d'actions en attente puis on lui refile la page en question. Il ne joue donc pas sur des données "par à jour".

Mettre à jour les données quand le joueur se repointe dans une situation d'interaction n'est pas satisfaisant
Faudra m'expliquer pourquoi

de même que le cron ne suffit pas
Je pense que l'explication là-dessus rejoindra celle de la précédente

Le cron peut gérer cette situation si tu fais une exécution dans l'ordre des événements
Oui, de même si la résolution est faite avant de servir la page au joueur. L'important est de bien comprendre qu'on stock une stack d'évènements datés (avec heure, minute secondes heinà, et que leur résolution ne se fait pas (nécessairement) à la date en question

mais il ne gérera pas un joueur E qui viendrait espionner la situation vécue dans le laps de temps où ça n'a pas été exécuté
Ben, oui, c'est pour ça qu'un démon (sauf quant à avoir un langage+stack+besoin conçu pour, cf jeux AAA) ou un cron minuté merdique n'ont pas leur place ici. Quand le joueur E va lancer son espionnage, on va résoudre ce qui concerne ce joueur puis lui afficher la page de lançage d'espionnage, il va le lancer, il est censé se faire à une date T, et il sera résolu à une date T' indépendante de T.

Le joueur E n'aura donc pas la vision du jeu à N+30s d'un événement arrivé à N parce que ton cron tourne à N+1m.
Oui, c'est pour cela que le principe du démon pu du... coude, peu importe la fenêtre de temps qu'on se fixe.

Tu peux en revanche le gérer de façon insatisfaisante en renvoyant le résultat au joueur E à N+1min, une fois que son propre événement est exécuté.
Je ne suis pas sûr de comprendre...

Par contre, je ne vois pas en quoi le fait d'avoir une cron (qui reste à proprement parler un démon) qui tourne multiplierait ton risque de bug puisque c'est quelque chose de parfaitement géré par le serveur.
Fais donc un CRON minuté qui tourne pendant quelques jours voire semaine: tu tomberas très certainement sur des erreurs "random" (ou plutôt, des erreurs rares de "pas de chance"): une BDD qui va se déconnecter sur un des appels du cron, ou qui aura eu de la latence, ou un pool de connexion qui va saturer parce que le serveur mouline un peu ce jour-là, etc


J'en reviens toujours au même exemple hein: quand tu veux fêter l'anniversaire de tes joueurs (leur anniversaire IRL ou le "bravo vous jouez depuis 1 an"), tu stockes une date et une heure, et la résout à la volée au moment où tu veux savoir si c'est son anniversaire. Tu ne fais pas un cron qui sauve "0s" en BDD, et qui incrémente ce compteur de 1 à chaque seconde (ou à chaque minute, ou un CRON journalier qui va incrémenter de 1 jour le nombre de jours pendant lesquels le joueur a joué). Tu sauves un point du temps, et tu résouts le problème sur la base de ce point du temps.

Si ton langage est conçu pour faire du "at", comme posé dans la question initiale, tu t'en sers, tu dis "at [telle date+heure], faire ça", et point barre. Comme c'est résolu, ce n'est pas dans ton "scope". Si ton langage n'en est pas capable (type PHP), tu ne bricole pas un CRON secondé/minuté ou je ne sais quelle daube pour l'émuler de travers.
D'ailleurs, même si ton langage est capable de gérer les "at", il faut quand même comprendre comment les choses vont se passer: ton batiment ne sera pas construit pile à 3H59. Supposons qu'à 3H58, l'armée de A attaque l'armée de B, et qu'il s'agisse de 2 grosses armées dont le caclul du combat va prendre 5 minutes, tu vas faire comment? Le batiment va se terminer 5 minutes plus tard (donc perdre 5 minutes de production) car le démon/cron/jsaispasquoi est séquentiel? Le batiment va se terminer pendant le calcul du combat (et planter ce calcul ou éventuellement l'altérer si ce batiment était une tourelle de défense de A)?

D'où le principe de base de décorréler le moment où un calcul se fait (3H58+5 = 4H03 pour la construction du batiment) et le moment dans le jeu où il est construit (3H59 in game).

Après, vous faites bien comme vous voulez, sur des jeux web amateur y'a pas souvent beaucoup de conséquence à ce genre de choses, mais bon, j'espère que vous n'êtes pas ingénieurs (peu importe le domaine), et que vous ne travaillez pas dans une banque ou une entreprise critique en matière de fiabilité/sécurité...
Répondre
#9
Bien évidemment que tu ne fais pas un calcul continu de la construction d'un bâtiment jusqu'à sa fin et que tu ne le fais qu'à la fin de l'exécution effective. Donc oui, si tu lances à 2h et que ça prend 4h, tu ne fais le calcul qu'à 6h, c'est évident ça. Tu ne vas pas le mettre à jour en continu. Donc non, tu n'as aucun espèce de compteur en bdd, juste une date. On est sur la même longueur d'onde à ce sujet.

La tâche cron n'est pas là pour faire un calcul continu de chaque opération, elle est là pour faire les calculs des opérations qui se terminent dans le laps de temps passé. Je ne dis rien de contraire à toi sur ce point.

Ce que je te dis, c'est que si tu fais des calculs qu'à la fin des événements, tu auras forcément un décalage pour quelqu'un qui est là. Donc oui, pourquoi pas en effet résoudre les conflits liés au joueur espionné. Il n'empêche que si tu te contentes de ça, ton joueur qui aura résolu ces conflits n'aura un retour qu'au moment de l'exécution du cron, soit potentiellement près d'une minute après la fin théorique effective pour lui. En cela, la tâche cron est nécessaire mais non suffisante.

Cette résolution, le joueur qui est là doit pouvoir la "forcer" pour que tout ce qui le concerne soit à jour au moment où ça doit l'être. Il peut donc mettre à jour cette liste d'événements qui se terminent. C'est bien sûr une solution de facilité qui ne peut pas fonctionner sur un nombre très important d'utilisateurs pour les raisons que tu évoques et qui seront que tu auras forcément des erreurs ici et là. Sur une population active restreinte en un temps t, si tu as une temporalité bien assez fine, le risque est assez mineur. Mais j'ai vu ce genre de problèmes sur des jeux fournis par des entreprises et non pas amateurs, il est vrai.

Si ton combat prend 5 minutes à se calculer, avec 2 joueurs seulement, tu as un grave problème d'optimisation. Mais on est d'accord qu'on suppose là que les traitements à effectuer sont sur des temps très brefs et qu'évidemment tu les calcules dans l'ordre chronologique, sans quoi tu auras un calcul fini avant un autre.



Quant à savoir si le cron est une merde ou non, c'est un autre sujet. Ca reste la solution la plus accessible et la moins impropre pour ce genre de problématiques dans les dimensions et besoins qui nous concernent et qui ne sont pas ceux des banques ou entreprises critiques.
Répondre
#10
j ai l impression (depuis le début) que vous êtes d accord sur a peu près tout sauf périodicité du cron, et le vocabulaire employé
plus un sujet compréhension des mots de l'autre qu'archi la discussion 16 relisez vous vous allez voir !
[WIP]projet Rivages
[WIP]projet Arthur (comme si ça suffisait pas d'un...)
Répondre


Sujets apparemment similaires...
Sujet Auteur Réponses Affichages Dernier message
  Histoire d'éxécution ?... Unkof 25 4 927 11-19-2009, 02:10 PM
Dernier message: Unkof



Utilisateur(s) parcourant ce sujet : 1 visiteur(s)