JeuWeb - Crée ton jeu par navigateur
Gestion des Ressources en 'temps réel' [Par Pascalr] - 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 : Gestion des Ressources en 'temps réel' [Par Pascalr] (/showthread.php?tid=158)



Gestion des Ressources en 'temps réel' [Par Pascalr] - Kevin - 02-09-2006

Tuto By Pascalr

De nombreuse méthodes existe pour les ressources, mais la plus part n'utilisent pas correctement les possibilités de la base de données.

Je vous ai donc fait un tutorial sur comment on fait pour que ce ne soit que de la base de données.

Soit 3 tables

production : Contient les types de production, le coef est le nombre standard de prod par 24h
Code PHP :
<?php 
CREATE TABLE
`production` (
  `prod_id` int(11) NOT NULL auto_increment,
  `prod_nom` varchar(64) NOT NULL default '',
  `prod_coef` float NOT NULL default '0',
  PRIMARY KEY  (`prod_id`)
)
ENGINE=MyISAM ;

utilisateurs : Contient les utilisateurs

Code PHP :
<?php 
CREATE TABLE
`utilisateurs` (
  `usr_id` int(11) NOT NULL auto_increment,
  `usr_name` varchar(64) default NULL,
  PRIMARY KEY  (`usr_id`)
)
ENGINE=MyISAM  ;

usine : Contient les usines de production, coef est le coeficient multiplicateur de l'usine, max est la quantité max que l'usine peut faire avant d'arréter de produire (plus de place)
Code PHP :
<?php 
CREATE TABLE
`usine` (
  `usine_id` int(11) NOT NULL auto_increment,
  `usine_prodid` int(11) NOT NULL default '0',
  `usine_usrid` int(11) NOT NULL default '0',
  `usine_coef` float NOT NULL default '0',
  `usine_qtt` int(11) NOT NULL default '0',
  `usine_max` int(11) NOT NULL default '0',
  `usine_last` timestamp NOT NULL default CURRENT_TIMESTAMP,
  `usine_reste` int(11) NOT NULL default '0',
  PRIMARY KEY  (`usine_id`)
)
ENGINE=MyISAM ;

On va 1° créer 100 utilisateurs et 100 productions

Code PHP :
<?php
   mysql_connect
('localhost','','') ;
   mysql_select_db('letest') ;
   for ($i=1; $i<101; $i++) {
      $sql = 'insert into utilisateurs (usr_name) values ("user'.$i.'")' ;
      mysql_unbuffered_query ($sql) ;
   }  
  
for ($i=1; $i<101; $i++) {
      $sql = 'insert into production (prod_nom, prod_coef)
            values ("prod'
.$i.'",1+rand()*100)' ;
      mysql_unbuffered_query ($sql) ;
   }  
  
echo 'c\'est fini' ;
?>

Et on creer 100 prod pour chaque utilisateurs (100) soit 10 000 prods

Code PHP :
<?php
   mysql_connect
('localhost','','') ;
   mysql_select_db('letest') ;
   $sql = ' insert into usine (usine_prodid, usine_usrid, usine_coef, usine_max)
            Select prod_id, usr_id, rand()+0.001, TRUNCATE(100+rand()*100,0)
               from utilisateurs, production'
;
   mysql_unbuffered_query ($sql) ;
   echo 'c\'est fini' ;
?>

Et oui créer 10000 lignes cela prend moins d'une seconde

bon la méthode c'est de regarder combien de production sont produites depuis la dernière connexion.

C'est (usine_coef*prod_coef) unité par 24h donc pour 86400 secondes
Mais comme il ne se passe pas forcément 24h entre chaque calcule, le nombre de secondes entre 2 calcule c'est (CURRENT_TIMESTAMP-usine_last)
Et la production c'est (usine_coef*prod_coef)*(CURRENT_TIMESTAMP-usine_last)/86400

Une disgression,
MySql stoque les TIMESSTAMP bizarement, il ne stock pas le nombre de secondes, mais le nombre de jour*100000 + nombre de secondes restantes.
Du coup CURRENT_TIMESTAMP-usine_last si il se passe + de 24h vas nous donner un résultat étrange.
on utilise alors UNIX_TIMESTAMP()-UNIX_TIMESTAMP(usine_last) qui nous donne le vrai nombre de seconde

2° problème que faire des fractions de production. on va utiliser reste pour stocker ce qui est en cours
la partie entiere pas de prob c'est TRUNCATE(calcule,0) ;
La partie fractionnaire c'est MOD(calcule,86400) ;

cela donne

Code PHP :
<?php 
Select TRUNCATE
( ( ( (UNIX_TIMESTAMP()-UNIX_TIMESTAMP(usine_last)) * (usine_coef*prod_coef) ) ) / 86400,0), MOD ( ( ( (UNIX_TIMESTAMP()-UNIX_TIMESTAMP(usine_last)) * (usine_coef*prod_coef) ) ) ,86400)
from usine join production on (prod_id=usine_prodid)

On voit que la query va devenir dure à lire, c'est pourquoi en PHP on la décompose.

Code PHP :
<?php
   mysql_connect
('localhost','','') ;
   mysql_select_db('letest') ;
   list($usec, $sec) = explode(" ", microtime());
   $debut = ((float)$usec + (float)$sec);
  
  
// on découpe la chaine pour réussir à se retrouver
   // temps passé
   $temps = '(UNIX_TIMESTAMP()-UNIX_TIMESTAMP(usine_last))' ;
   // coef de production
   $coef = '(usine_coef*prod_coef)' ;
   // production avec les parenthèse (ne pas les oublier)
   $prod = '('.$temps.'*'.$coef.')' ;
  
   $sql
= 'Update usine join production on (prod_id=usine_prodid) set
           usine_qtt = usine_qtt + TRUNCATE ( ('
.$prod.'+usine_reste)/86400,0),
           usine_reste = MOD ( ('
.$prod.'+usine_reste),86400),
           usine_last = CURRENT_TIMESTAMP'
;
   mysql_unbuffered_query ($sql) ;
  
  
  
list($usec, $sec) = explode(" ", microtime());
   $fin =((float)$usec + (float)$sec);
   $reste = $fin-$debut ;
   echo 'fait en '.$reste.' secondes' ;
?>
Fait en 0.09s pour 10000 lignes

Bon faut tester le max on change juste la query en

Code PHP :
<?php 
   $sql
= 'Update usine join production on (prod_id=usine_prodid) set
           usine_qtt =
              if (usine_qtt + TRUNCATE (
('
.$prod.'+usine_reste)/86400,0)>usine_max,
                 usine_max,
               usine_qtt + TRUNCATE ( ('
.$prod.'+usine_reste)/86400,0)),
           usine_reste = MOD ( ('
.$prod.'+usine_reste),86400),
           usine_last = CURRENT_TIMESTAMP'
;

Et voila, on vat tester réellement le temps si beaucoup de lignes sont anciennes

Code PHP :
<?php 
Update usine set usine_last
= usine_last - INTERVAL TRUNCATE(rand()*20,0) DAY

on vient de changer les dates avec de -0 à -19 jours (0.05s pour 10000)

on relance le calcule, toujours 0.09s
Je fabrique 100 000 lignes (lancer 9 fois la page de fab de prod)
Ca passe 0.9 seconde

Avec un million de lignes
environt 10s

donc pour résoudre il suffit de ne faire que les 10000 lignes les plus anciennes à chaque click
Comme le order n'est possible que sur une seule table dans l'update, on change

Code PHP :
<?php 
$coef
= '(usine_coef*(select prod_coef from production where prod_id=usine.usine_prodid))' ;

et

Code PHP :
<?php 
   $sql
= 'Update usine set
           usine_qtt =
              if (usine_qtt + TRUNCATE (

('
.$prod.'+usine_reste)/86400,0)>usine_max,
                 usine_max,
               usine_qtt + TRUNCATE ( ('
.$prod.'+usine_reste)/86400,0)),
           usine_reste = MOD ( ('
.$prod.'+usine_reste),86400),
           usine_last = CURRENT_TIMESTAMP
         order by usine_last  
         Limit 10000'
;

Donc maintenant je met 0.18 (et oui le select dans le update est plus long) mais je mettrais toujours 0.18 secondes

Amicalement, pascal [ le rédacteur si vous souhaitez faire difuser ce tutorial merci de le contacter ICI.


RE: Gestion des Ressources en 'temps réel' - orditeck - 02-09-2006

L'aide pour ce tutoriel ce trouve à cette adresse :
http://www.jeuweb.org/board/showthread.php?tid=258

Ce membre a eu l'autorisation de recopier ce tutoriel depuis l'ancien Forum.