Авторы: Arkshine & xPaw
Как вы знаете вывести в MOTD страничку, сформированную в вашем плагине довольно просто, а вот добиться двустороннего взаимодействия MOTD уже не такая тривиальная задача. В этой статье вы узнаете, как это сделать.
Зачем же это нужно? Например, для создания своего классного магазина или выбора класса игрока, применений масса.
Требования:
Для осуществления взаимодействия вам понадобятся:
- SourceQuery.class.php
- Вебсайт
Так же вы должны в какой-то мере владеть:
- PAWN
- PHP
- HTML/CSS (желательно)
Приступаем!
В этой статье будет описано, то, как сделать MOTD для выбора класса игрока.
План статьи:
- Как это работает?
- PHP код
- AMXX плагин
- Итоги и Скриншоты
Как это работает?
Мы будем показывать игроку меню в MOTD, в котором он сможет куда-либо нажать.
Когда игрок сделает действие (нажмёт на ссылку), вебсайт отошлёт всю нужную информацию на сервер (hlds), и затем плагин обработает эту информацию.
Для реализации мы регистрируем серверную команду через register_concmd.
Например register_concmd(“php_result”, “callback”).
При выполнении команды php_result через RCON мы передаём ей некоторые параметры, которые затем читаем в функции callback.
В итоге получается такая схема взаимодействия:
Сервер -> Вебсайт -> Сервер
PHP код
Скрипт получает следующую информацию:
- Id игрока
- IP игрока
- Текущий класс игрока
Итак, начинаем:
<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>
После этой проверки, мы можем показать игроку меню:
<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 в скрипт.
Окончательный вариант кода: (в коде есть дефайны, которые нужно поменять)
<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.
#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, если у игрока нет класса
Так же сразу будем выдавать оружие игроку при выборе класса, если до этого игрок был без класса.
#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
По поводу неточностей или ошибок в переводе пишите в комментарии.





Sorry, the comment form is closed at this time.