1. Ce site utilise des "témoins de connexion" (cookies) conformes aux textes de l'Union Européenne. Continuer à naviguer sur nos pages vaut acceptation de notre règlement en la matière. En savoir plus.

Échanges AMXX <-> PHP via un MOTD

Création d'un système d'achat

  1. Midori
    Table des matières

    Introduction & pré-requis

    Vous avez toujours voulu vous servir du MOTD de CS 1.6/CS:CZ pour y faire un "shop" ou autre ?

    Pour ce genre de plugin, il est préférable de maîtriser :
    • PHP
    • HTML
    • CSS
    Vous aurez également besoin :
    • Du fichier SourceQuery.class.php créé par xPaw (permets d'envoyer des commandes au serveur via le RCON).
    • D'un hébergement web car ça ne fonctionnera pas si les fichiers sont sur le serveur.
    Et c'est tout. :) 

    Pour ce tutoriel, je vais choisir un type de MOTD AMXX/PHP plutôt facile à comprendre, il s'agit de classes.
    (Je pourrais prochainement mettre du code à la fin de ce tutoriel pour montrer comme ce serait avec un "shop")

    Comment ça fonctionne ?

    Une page MOTD sera ouverte quand souhaitée, affichant ainsi un menu sur lequel le joueur pourra cliquer dessus.
    Lorsque le joueur cliquera sur un lien de la page, le site enverra toutes les informations au serveur, et c'est ensuite notre plugin qui fera le reste.

    Le site enverra les informations au serveur via le RCON, avec la commande, nommée par exemple, php_results.
    Le serveur les récupérera avec la fonction register_concmd.

    En résumé : Serveur -> Site -> Serveur

    Le code en PHP

    Nous aurons à récupérer quelques données venant du serveur :
    • L'index du joueur ;
    • L'adresse IP du joueur ;
    • Sa classe actuelle.
    Pourquoi récupérer son IP ? (open)
    En fait, c'est une sécurité, car, si un petit malin venait à trouver le lien de votre page, il pourrait faire comme si le joueur avait choisi un item, alors que ce n'est pas le cas !

    Voici le début du code, avec l'incrustation du HTML (on ne va pas faire de design pour ce tutoriel) :
    Code (PHP):

    <html><head><title>Mon super shop</title></head><body>
     
    <?php
        $s_index = $_GET[ 'index' ];
        $s_ip = $_GET[ 'ip' ];
        $s_class = $_GET[ 'class' ];
        $ip = $_SERVER[ 'REMOTE_ADDR' ];
     
        /*
        Si l'IP reçue du serveur n'est pas la même que celle
        de la personne qui va sur le site, on affiche rien
        */

     
        if( $ip != $s_ip )
        {
            die( );
        }
    ?>
    </body></html>
     
    Après ce petit test de sécurité, on peut afficher les items du MOTD au joueur :
    Code (PHP):
    <html><head><title>Mon super shop</title></head><body>[/LEFT]
     
    <?php
        $s_index = $_GET[ 'index' ];
        $s_ip = $_GET[ 'ip' ];
        $s_class = $_GET[ 'class' ];
        $ip = $_SERVER[ 'REMOTE_ADDR' ];
     
        if( $ip != $s_ip )
        {
            die( );
        }
        else
        {
            // On créé un tableau où on met le nom de tous les items
            $nomDesItems = array( "M4A1 + USP", "Ak47 + GLOCK", "FAMAS + DEAGLE", "GALIL + DEAGLE" );
     
            /* On fait une boucle FOR qui permettra de réduire
            considérablement les lignes s'il y a plus d'items */

     
            for( $x = 0; $x < count( $nomDesItems ); $x ++ )
            {
                Echo "<a href=\"". $_SERVER[ 'PHP_SELF' ] ."?item=". ( $x + 1 ) ."&index=". $s_index ."&class=". $s_class ."&ip=". $s_ip ."\">". $nomDesItems[ $x ] ."</a><br/><br/>";
            }
        }
    ?>
    </body></html>
     
    Et maintenant, il ne reste plus qu'à récupérer l'évènement lorsque le joueur choisit item : c'est assez simple, il suffit d'utiliser $_GET[ 'item' ].

    Cependant, il faudra envoyer la commande uniquement si la classe du joueur est différente de l'item.
    C'est à ce moment là que l'on va utiliser la classe de xPaw.

    J'ajoute au début du code, les quelques defines que vous devrez changer pour que ça fonctionne (j'ai laissé le time out à 3, par défaut) :
    Code (PHP):
    <html><head><title>Mon super shop</title></head><body>
     
    <?php
        define( 'TIME_OUT', 3 );
        define( 'SERV_PORT', port_de_votre_serveur );
        define( 'SERV_IP', 'ip_de_votre_serveur' );
        define( 'SERV_RCON', 'rcon_de_votre_serveur' );
     
      // N'oubliez pas de placer ce fichier créé par xPaw dans le FTP
        require 'SourceQuery.class.php';
     
        $s_index = $_GET[ 'index' ];
        $s_ip = $_GET[ 'ip' ];
        $s_class = $_GET[ 'class' ];
        $item = $_GET[ 'item' ];
        $ip = $_SERVER[ 'REMOTE_ADDR' ];
     
        if( $ip != $s_ip )
        {
            die( );
        }
        else if( $item ) // Un item a été choisi par le joueur, on envoie la commande
        {
            if( $class != $item ) // Si sa classe est différente de celle qu'il a déjà
            {
                $query = new SourceQuery( );
     
                try
                {
                    $query -> Connect( SERV_IP, SERV_PORT, TIME_OUT, SourceQuery :: GOLDSOURCE ); // On se connecte
                    $query -> SetRconPassword( SERV_RCON ); // On met le RCON
                    $query -> Rcon( 'php_results  '. $s_index .' '. $item.' '. $ip ); // On envoie le RCON
                }
                catch( SQueryException $e )
                {
                    echo $e -> getMessage( );
                }
     
                $query -> Disconnect( ); // On se déconnecte
            }
            else // Sinon on le redirige sur la page
            {
                header( 'Location: '. $_SERVER[ 'PHP_SELF' ] .'?index='. $s_index .'&class='. $s_class .'&ip='. $s_ip .'' );
            }
        }
     
        else
        {
            $nomDesItems = array( "M4A1 + USP", "Ak47 + GLOCK", "FAMAS + DEAGLE", "GALIL + DEAGLE" );
     
            for( $x = 0; $x < count( $nomDesItems ); $x ++ )
            {
                Echo "<a href=\"index.php?item=". ( $x + 1 ) ."&index=". $s_index ."&class=". $s_class ."&ip=". $s_ip ."\">". $nomDesItems[ $x ] ."</a><br/><br/>";
            }
        }
     
    ?>
    </body></html>
    Voilà, le code PHP est maintenant terminé.
    Vous pouvez bien sûr faire votre propre design, voici ce que j'ai réussi à faire avec mon MOTD, c'est plutôt sympa :

    [​IMG]

    Le code en PAWN

    Tout d'abord, on va commencer par la réception des données que le site à envoyé via RCON.
    Je rappelle que la commande utilisée dans notre exemple est : php_results.

    Code (C):
    #include <amxmodx>
     
    new MaxServerSlots;
     
    public plugin_init( )
    {
        register_plugin( "AMXX/PHP MOTD", "1.0.0", "Bboy Grun" );
     
        register_concmd( "php_results", "OnResultShop" );
     
        MaxServerSlots = get_maxplayers();
    }
     
    public OnResultShop( const idServer )
    {
        if( idServer )
        {
            // On vérifie que c'est le serveur qui fait la commande (0 comme index)
            return;
        }
     
        new arguments[ 25 ];
     
        if( !read_args( arguments, charsmax( arguments ) ) )
        {
            // On lit les arguments et on arrête là si il y a aucune chaîne de caractères.
            return;
        }
     
        new ipPHP[ 16 ], idStr[ 3 ], itemStr[ 3 ];
     
        if( parse( arguments, idStr, charsmax( idStr ), itemStr, charsmax( itemStr ), ipPHP, charsmax( ipPHP ) ) != 3 )
        {
            // On veut 3 arguments. On arrête là si pour une raison ou une autre, il n'y aurait pas ce compte.
            return;
        }
     
        new const player = str_to_num( idStr );
     
        // Sécurité - Doit être un joueur valide.
        if( 1 <= player <= MaxServerSlots )
        {
            new ip[ 16 ];
            get_user_ip( player, ip, charsmax( ip ), 1 );
     
            // Comme sur le site, on re-vérifie les IP
            if( equal( ip, ipPHP ) )
            {
                // On peut continuer
            }
        }
    }
     
    Voilà, on est arrivé à lire les données !

    Mais pour finir ce tutoriel, il faut faire le système des classes, donner l'arme à l'apparition du joueur, montrer le MOTD si le joueur n'a pas de classe, donner les armes directement si le joueur n'avait pas de classes avant, et ainsi de suite...

    Voici un example :

    Code (C):
    #include <amxmodx>
    #include <fun>
    #include <cstrike>
    #include <hamsandwich>
     
    const MaxClients = 32;
     
    new PlayerClass[ MaxClients + 1 ];
    new PlayerNextClass[ MaxClients + 1 ];
     
    new MaxServerSlots;
     
    // Là où vous avez mis votre MOTD.
    new const URL[] = "http://mon-site.com/index.php";
     
    public plugin_init( )
    {
        register_plugin( "AMXX/PHP MOTD", "1.0.0", "Bboy Grun" );
     
        RegisterHam( Ham_Spawn, "player", "OnPlayerSpawn", .Post = true );
     
        register_clcmd( "say /class", "OnChooseClass" );
        register_concmd( "php_results", "OnShopResult" );
     
        MaxServerSlots = get_maxplayers();
    }
     
    public OnPlayerSpawn( const player )
    {
        if( is_user_alive( player ) )
        {
            if( !PlayerClass[ player ] )
            {
                OnChooseClass( player );
            }
            else
            {
                new const nextClass = PlayerNextClass[ player ];
     
                if( nextClass )
                {
                    PlayerClass[ player ] = nextClass;
                    PlayerNextClass[ player ] = 0;
                }
     
                give_weapons( player, nextClass );
            }
        }
    }
     
    public client_disconnect( client )
    {
        PlayerNextClass[ client ] = 0;
        PlayerClass[ client ] = 0;
    }
     
    public OnChooseClass( const player )
    {
        new infos[ 128 ], ip[ 16 ];
        get_user_ip( player, ip, charsmax( ip ), 1 );
     
        formatex( infos, charsmax( infos ), "%s?index=%d&ip=%s&class=%d", URL, player, ip, PlayerClass[ player ] );
        show_motd( player, infos );
    }
     
    public OnShopResult( const idServer )
    {
        if( idServer )
        {
            return;
        }
     
        new arguments[ 25 ];
     
        if( !read_args( arguments, charsmax( arguments ) ) )
        {
            return;
        }
     
        new ipPHP[ 16 ], idStr[ 3 ], itemStr[ 3 ];
     
        if( parse( arguments, idStr, charsmax( idStr ), itemStr, charsmax( itemStr ), ipPHP, charsmax( ipPHP ) ) != 3 )
        {
            return;
        }
     
        new const player = str_to_num( idStr );
     
        if( 1 <= player <= MaxServerSlots )
        {
            new ip[ 16 ];
            get_user_ip( player, ip, charsmax( ip ), 1 );
     
            if( equal( ip, ipPHP ) )
            {
                new const item = str_to_num( itemStr );
                new const currentClass = PlayerClass[ player ];
     
                if( currentClass )
                {
                    if( currentClass != item )
                    {
                        PlayerNextClass[ player ] = item;
                    }
                }
                else
                {
                    PlayerClass[ player ] = item;
     
                    if( is_user_alive( player ) )
                    {
                        give_weapons( player, item );
                    }
                }
            }
        }
    }
     
    give_weapons( const player, const item )
    {
        #define give_items(%1,%2,%3,%4) ( give_item( %1, %2 ), cs_set_user_bpammo( %1, %3, %4 ) )
     
        strip_user_weapons( player );
        give_item( player, "weapon_knife" );
     
        switch( item )
        {
            case 1:
            {
                give_items( player, "weapon_m4a1", CSW_M4A1, 90 );
                give_items( player, "weapon_usp", CSW_USP, 100 );
            }
            case 2:
            {
                give_items( player, "weapon_ak47", CSW_AK47, 90 );
                give_items( player, "weapon_glock18", CSW_GLOCK18, 120 );
            }
            case 3:
            {
                give_items( player, "weapon_famas", CSW_FAMAS, 90 );
                give_items( player, "weapon_deagle", CSW_DEAGLE, 35 );
            }
            case 4:
            {
                give_items( player, "weapon_galil", CSW_GALIL, 90 );
                give_items( player, "weapon_deagle", CSW_DEAGLE, 35 );
            }
        }
    }
     

    En conclusion

    Le seul conseil que j'ai à donner : ne dépassez jamais la dimension 600x350 pour les images dans un MOTD, pour qu'il soit dans les bonnes tailles à toutes les résolutions.

    C'est à vous maintenant de faire votre Shop/Classe MOTD, de faire votre design et d'inclure vos idées.
    Grâce à ce système, vous pourrez faire des shops qui sortent de l'ordinaire, par exemple un shop Killing Floor dans un MOTD de CZ...

    J'espère que ce tutoriel sera et est apprécié, merci 1000 fois à xPaw pour sa classe en PHP, sans elle, il aurait été impossible d'envoyer des commandes RCON au serveur et donc, impossible de faire ce genre de MOTD.

Commentaires récents

  1. Arkshine
    Arkshine
    5/5,
    Merci pour ce tutoriel, bien utile !
Chargement...