К содержимому

Взаимодействие MOTD и AMXX через PHP

Как вы знаете вывести в MOTD страничку, сформированную в вашем плагине довольно просто, а вот добиться двустороннего взаимодействия MOTD уже не такая тривиальная задача. В этой статье вы узнаете, как это сделать. Зачем же это нужно? Например, для создания своего классного магазина или выбора класса…

ПриложениеCounter-Strike 1.6Просмотры:65Комментарии:0

Описание

Как вы знаете вывести в MOTD страничку, сформированную в вашем плагине довольно просто, а вот добиться двустороннего взаимодействия MOTD уже не такая тривиальная задача. В этой статье вы узнаете, как это сделать.
Зачем же это нужно? Например, для создания своего классного магазина или выбора класса игрока, применений масса.

Вот пример:

80_screenshots_2012-07-31_00001

Требования:

Для осуществления взаимодействия вам понадобятся:

Так же вы должны в какой-то мере владеть:

  • PAWN
  • PHP
  • HTML/CSS (желательно)

Приступаем!

В этой статье будет описано, то, как сделать MOTD для выбора класса игрока.

План статьи:

  • Как это работает?
  • PHP код
  • AMXX плагин
  • Итоги и Скриншоты

Как это работает?

Мы будем показывать игроку меню в MOTD, в котором он сможет куда-либо нажать.
Когда игрок сделает действие (нажмёт на ссылку), вебсайт отошлёт всю нужную информацию на сервер (hlds), и затем плагин обработает эту информацию.

Для реализации мы регистрируем серверную команду через register_concmd.
Например register_concmd("php_result", "callback").
При выполнении команды php_result через RCON мы передаём ей некоторые параметры, которые затем читаем в функции callback.

В итоге получается такая схема взаимодействия:
Сервер -> Вебсайт -> Сервер

PHP код

Скрипт получает следующую информацию:

  • Id игрока
  • IP игрока
  • Текущий класс игрока

Итак, начинаем:

PHP
<html><head><title>Class Chooser</title></head><body>
 
<?php
    $s_index = $_GET[ 'index' ];
    $s_ip = $_GET[ 'ip' ];
    $s_class = $_GET[ 'class' ];
    $ip = $_SERVER[ 'REMOTE_ADDR' ];
 
    /*
        Если полученный IP с сервера не совпадает с реальным IP игрока,
        то прекращаем работу скрипта.
    */
 
    if( $ip != $s_ip )
    {
        die( );
    }
?>
</body></html>

После этой проверки, мы можем показать игроку меню:

PHP
<html><head><title>Class Chooser</title></head><body>
 
<?php
    $s_index = $_GET[ 'index' ];
    $s_ip = $_GET[ 'ip' ];
    $s_class = $_GET[ 'class' ];
    $ip = $_SERVER[ 'REMOTE_ADDR' ];
 
    if( $ip != $s_ip )
    {
        die( );
    }
    else
    {
        // Создаём массив из доступных классов
        $classesName = array( "M4A1 + USP", "Ak47 + GLOCK", "FAMAS + DEAGLE", "GALIL + DEAGLE" );
 
        // Теперь в цикле создаём элементы меню
 
        for( $x = 0; $x < count( $classesName ); $x ++ )
        {
            Echo "<a href="". $_SERVER[ 'PHP_SELF' ] ."?item=". ( $x + 1 ) ."&index=". $s_index ."&class=". $s_class ."&ip=". $s_ip ."">". $classesName[ $x ] ."</a><br/><br/>";
        }
    }
?>
</body></html>

Теперь мы должны отослать серверу информацию о том какой класс выбрал игрок.

Но мы отошлём команду, только в том случае, если текущий класс игрока отличается от того, который игрок выбрал.
Теперь пришло время подключить SourceQuery.class.php в скрипт.

Окончательный вариант кода: (в коде есть дефайны, которые нужно поменять)

PHP
<html><head><title>Class Chooser</title></head><body>
 
<?php
    define( 'TIME_OUT', 3 );
    define( 'SERV_PORT', port_of_your_server ); // Сменить на порт сервера
    define( 'SERV_IP', 'ip_of_your_server' );   // Сменить на ip сервера
    define( 'SERV_RCON', 'rcon_of_your_server' ); // Сменить на RCON сервер
 
    // Не забудьте залить класс SourceQuery на 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 ) // Если был выбран пункт меню, то отсылаем команду ...
    {
        if( $class != $item ) // ... продолжаем только если текущий класс игрока не совпадает с выбранным.
        {
            $query = new SourceQuery( );
 
            try
            {
                $query -> Connect( SERV_IP, SERV_PORT, TIME_OUT, SourceQuery :: GOLDSOURCE ); // Подключяемся к серверу
                $query -> SetRconPassword( SERV_RCON ); // Задаём RCON
                $query -> Rcon( 'php_results  '. $s_index .' '. $item.' '. $ip ); // Отсылаем команду
            }
            catch( SQueryException $e )
            {
                echo $e -> getMessage( );
            }
 
            $query -> Disconnect( ); // Завершаем соединение
        }
        else // ... выбранный класс равен текущему классу игрока, редирект на страницу выбора класса (по сути на эту же станицу)
        {
            header( 'Location: '. $_SERVER[ 'PHP_SELF' ] .'?index='. $s_index .'&class='. $s_class .'&ip='. $s_ip .'' );
        }
    }
 
    else
    {
        $classesName = array( "M4A1 + USP", "Ak47 + GLOCK", "FAMAS + DEAGLE", "GALIL + DEAGLE" );
 
        for( $x = 0; $x < count( $classesName ); $x ++ )
        {
            Echo "<a href="". $_SERVER[ 'PHP_SELF' ] ."?item=". ( $x + 1 ) ."&index=". $s_index ."&class=". $s_class ."&ip=". $s_ip ."">". $classesName[ $x ] ."</a><br/><br/>";
        }
    }
 
?>
</body></html>

На этом с PHP всё.

AMXX плагин

Для начала получим информацию отосланную с вебсайта (через RCON)
Мы использовали команду php_result.

Pawn
#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 ) // idServer должен быть равен 0 (нельзя допустить чтоб игрок мог использовать эту команду)
    {
        new arguments[ 25 ];
     
        if( read_args( arguments, charsmax( arguments ) ) ) // Получаем аргументы, если их нет, то прекращаем работу
        {
            new ipPHP[ 16 ], idStr[ 3 ], itemStr[ 3 ];
            
            // Парсим 3 аргумента, если их не 3, то прекращаем работу
            if( parse( arguments, idStr, charsmax( idStr ), itemStr, charsmax( itemStr ), ipPHP, charsmax( ipPHP ) ) == 3 )
            {
                new const player = str_to_num( idStr );
     
                // Проверка на то, что в player содержится id игрока
                if( 1 <= player <= MaxServerSlots )
                {
                    new ip[ 16 ];
                    get_user_ip( player, ip, charsmax( ip ), 1 );
                    
                    // Как и в PHP, мы должны сверить IP адреса
                    
                    if( equal( ip, ipPHP ) )
                    {
                        // Можем продолжать
                    }
                }
            }
        }
    }
}

Отлично, мы получили всю информацию, которая нужна.
Теперь завершим плагин, добавим следующую функциональность:

  • Выдача оружия игроку при респавне
  • Показ MOTD, если у игрока нет класса

Так же сразу будем выдавать оружие игроку при выборе класса, если до этого игрок был без класса.

Pawn
#include < amxmodx >
#include < fun >
#include < cstrike >
#include < hamsandwich >
 
const MaxClients = 32;
 
new PlayerClass[ MaxClients + 1 ];
new PlayerNextClass[ MaxClients + 1 ];
 
new MaxServerSlots;
 
// Путь до скрипта
new const URL[ ] = "http://my-website.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", "OnResultShop" );
   
    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 OnResultShop( const idServer )
{
    if( !idServer )
    {
        new arguments[ 25 ];
     
        if( read_args( arguments, charsmax( arguments ) ) )
        {
            new ipPHP[ 16 ], idStr[ 3 ], itemStr[ 3 ];
            
            if( parse( arguments, idStr, charsmax( idStr ), itemStr, charsmax( itemStr ), ipPHP, charsmax( ipPHP ) ) == 3 )
            {
                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 );
        }
    }
}

В заключение

Единственное, что можно ещё сказать, не делайте изображения больше чем 600х350 в MOTD.
Картинка с таким размером будет приемлемо выглядеть на всех разрешениях экрана.

Теперь вы можете создать свой магазин или что угодно, со своим дизайном и прочим.

SourceQuery.class.php

Перевод: Polarhigh
Источник: http://forums.alliedmods.net/showthread.php?t=198774

По поводу неточностей или ошибок в переводе пишите в комментарии.

Благодарности

Авторы: Arkshine & xPaw

Комментарии

Комментариев пока нет.

Похожие

Обновление до 1.1.3: добавлена поддержка angled спрайтов (только импорт), добавлена опция Force 256 Pallete для расширения палитры до 256 цветов, исправлена ошибка при попытке сохранения спрайта с шириной не кратной 4 Плагин для импорта и экспорта HL спрайтов для растрового графического редактора…

Плагин для GIMP, позволяющий импортировать и экспортировать спрайты из игры Half-Life. Требования: Растровый редактор GIMP, рекомендуемая версия GIMP >= 2.10. Python модуль gimpfu для GIMP. Установка: Загрузите и извлеките директорию file-spr в каталог плагинов для GIMP: Windows: C:\Users\имя…

Приложение

HL MDL Unlock

Декомпилятор моделей с похожей функциональностью Бывает такое, что попадается модель, которую нельзя декомпилировать или поставить на сервер. Тогда на помощь приходит HL MDL Unlock. Приложение исправляет большинство ошибок (исправляет недопустимые названия текстур, мешей, анимаций, костей и т.п.)…