Как вывести SteamID в SourceQuery?

DOVE

GLite Inc.
Сообщения
296
Реакции
54
Я тут решил повторить гения и вывести список онлайна серверов на сайт, вот что вышло
upload_2019-1-25_22-50-17.png
На стадии добавления управления игроком возник вопрос, как узнать SteamID игрока на сервере. На сколько я понимаю в SB++ не используется база игроков онлайн, тогда как он получает SteamID? И что самое главное, как это получить мне?
 

iSe7en

Участник
Сообщения
209
Реакции
112
Посылай status и парси его либо пиши свой плагин
 
  • Мне нравится
Реакции: DOVE

DOVE

GLite Inc.
Сообщения
296
Реакции
54
@Se7en_RUS,
Посылай status и парси его либо пиши свой плагин
статус приходит, и я получаю IDшники, но если проверить, то они идут не в том порядке что у SQ
upload_2019-1-26_6-34-17.png
upload_2019-1-26_6-38-45.png
У меня еще мало опыта и я не могу быть уверенным в своих действиях, но... Можно как-то искать по массиву? К примеру я делаю сравнение имени в SQ и имени в status, а то что мне выдаст я просто через stristr обрезаю. Это реально?
upload_2019-1-26_6-49-4.png
 
Последнее редактирование:

Kruzya

Участник
Сообщения
12,970
Реакции
10,927
  • Команда форума
  • #4
Регуляркой лучше вытягивай игроков.
 
  • Мне нравится
Реакции: DOVE

iSe7en

Участник
Сообщения
209
Реакции
112
Какой то мой очень старый код, но на ксго исправно инфу парсил
C-подобный:
$Query->Connect($server->ip, $server->port, 3, SourceQuery::SOURCE);
$Query->SetRconPassword($server->rcon); // Выставляем rcon пароль
$return = $Query->Rcon('status'); // Посылаем команду на сервер

if (!isset($return) or empty($return)) {
    throw new Exception('Пустой ответ от сервера');
    continue;
}

$return = preg_replace('/[^0-9а-яА-Яa-zA-Z-_,!.:#|\n \[\ \]\ \/\ ()"]/ui', '', $return); // очищаем вывод
$return = explode("\n", trim($return)); // Разбиваем по строкам
$return = array_values(array_filter($return));

serverInfo = [];

// Название сервера
if (strpos($return[0], 'hostname') !== false) {
    $serverInfo['name'] = trim(explode(':', $return[0])[1]);// Название сервера
}

// Версия, токен, VAC
if (strpos($return[1], 'version') !== false) {
    $versionRow = explode(':', $return[1]);
    $tokenRow = explode('[', $versionRow[1]);

    $serverInfo['version'] = intval(preg_replace('/[^0-9]/', '', trim(explode('/', $versionRow[1])[0]))); // Версия сервера
    $serverInfo['gslt'] = (end($tokenRow) == 'G') ? 1 : 0; // Есть ли токен
    $serverInfo['secure'] = (strpos($tokenRow[0], 'secure') !== false) ? 1 : 0; // Включен ли VAC
}

// OS сервера
if (strpos($return[3], 'os') !== false) {
    $serverInfo['os'] = trim(explode(':', $return[3])[1]);
}

// Карта
if (strpos($return[5], 'map') !== false) {
    $serverInfo['map'] = preg_replace(array('(workshop/.*./)', '(/.*./)'), '', strtolower(trim(explode(':', $return[5])[1])));
    if (empty($serverInfo['map'])) $serverInfo['map'] = NULL;
}

// GOTV
$serverInfo['gotv'] = (strpos($return[6], 'gotv') !== false) ? 1 : 0;

// Информация о количестве игроков
$offset = ($serverInfo['gotv'] == 1) ? 7 : 6;
if (strpos($return[$offset], 'players') !== false) {
    $playersRow = trim(explode(':', $return[$offset])[1]);
    $botsRow = explode('bots', $playersRow);
    $maxplayersRow = explode('(', $botsRow[1])[1];

    $botsRow = explode(', ', $botsRow[0]);
    $serverInfo['bots'] = intval(end( $botsRow ));
    $serverInfo['players'] = intval(trim(explode('humans', $playersRow)[0]));
    $serverInfo['maxplayers'] = intval(explode('/', $maxplayersRow)[0]) - $serverInfo['bots'];
}

// Массив с игроками сервера
$offset = (strpos($return[7], 'userid') == true) ? 8 : 9;
$players = array_slice($return, $offset, -1);

foreach ($players as $player) {
    // Разбиваем строку
    $playerChunkID = trim(explode('"', $player)[0]);
    $rowPlayer = explode('"', $player);
    $playerChunkInfo = array_values(
        array_filter(
            explode(' ', trim(end( $rowPlayer )))
        )
    );

    if ($playerChunkInfo[0] == 'BOT') continue; // Пропускаем, если это бот

    $playerSteamID = $playerChunkInfo[0]; // SteamID
    if ($playerSteamID == 0) continue; // Пропускаем, если нет стимд

    $playerInfo[$playerSteamID]['name'] = $rowPlayer[1]; // Имя игрока на сервере
    $playerInfo[$playerSteamID]['id'] = intval(explode(' ', $playerChunkID)[1]); // ID игрока на сервере
    // Время на сервере
    $time_to_unix = explode(':', $playerChunkInfo[1]);
    if (count($time_to_unix) == 3) {
        $playerInfo[$playerSteamID]['server-time'] = ($time_to_unix[0] * 60 * 60) + ($time_to_unix[1] * 60) + $time_to_unix[2];
    } else {
        $playerInfo[$playerSteamID]['server-time'] = ($time_to_unix[0] * 60) + $time_to_unix[1];
    }

    $ipChunk = isset($playerChunkInfo[6]) ? 6 : 5;
    $playerInfo[$playerSteamID]['ip'] = explode(':', $playerChunkInfo[$ipChunk])[0];
}
 
  • Мне нравится
Реакции: DOVE

DOVE

GLite Inc.
Сообщения
296
Реакции
54
@Se7en_RUS, большое спасибо за готовое решение, но есть одно "но". Каждый раз при загрузке страници на сервер идет status. А если страницу загрузить 400 раз за секунду? Выходит что использовать этот код для вывода всей инфы о сервере никак не вариант
 

NaN

FPE_INTDIV_TRAP
Сообщения
1,513
Реакции
1,487
@Se7en_RUS, большое спасибо за готовое решение, но есть одно "но". Каждый раз при загрузке страници на сервер идет status. А если страницу загрузить 400 раз за секунду? Выходит что использовать этот код для вывода всей инфы о сервере никак не вариант
Нужно кэшировать куда-то информацию, обычно это делается в БД
 
  • Мне нравится
Реакции: DOVE

DOVE

GLite Inc.
Сообщения
296
Реакции
54
Нужно кэшировать куда-то информацию, обычно это делается в БД
неа, я тут решил включить свою мозг. Выходит что при нажатии на бан игрока идет перенаправление на скрипт, в который через _POST передается ник игрока. Потом как я понимаю можно сделать поиск по массиву
Из за кеширования можно забанить не того человека, который возьмет такой же ник как у того, кого вы захотите забанить
--- Добавлено позже ---
По сути это можно использовать для вывода ID
PHP:
        echo $banname, '*********</br>';
            $pieces = explode('#', $array);
            for ($i = 3; $i <= 64; $i++) //64 - устанавливает макс кол-во циклов чтоб не положить апачи.
            {
                $stristr = stristr($pieces[$i], '"');//проверки на совпадение в массиве
                $str = strtok($stristr, '"');
                if($banname == $str):
                    break; //останавливает цикл если найден результат
                endif;
            }

            $steamID = $pieces[$i];
            $stristr_id = stristr($steamID, 'STEAM_1:');
            $str_id = strtok($stristr_id, ' ');
     
            $stristr_name = stristr($steamID, '"');
            $str_name = strtok($stristr_name, '"');
            echo $str_name;
            echo $str_id;
Решение найдено, думаю можно закрывать тему. Всем большое спасибо :)
 
Последнее редактирование:

Reiko1231

AlexTheRegent
Сообщения
508
Реакции
1,336
@DOWE, в статусе передается не только ник, но так же userid и steamid. Кешируйте пару userid+name и тогда не промахнётесь баном (и баньте так же по userid или steamid).
 

DOVE

GLite Inc.
Сообщения
296
Реакции
54
@Reiko1231, ну да, я так и сделал. Когда нажимаешь на Бан, то идет перенаправление и передает туда ник. В цикле сравниваеются два массива, в одном ники, во втором SteamID. При совпадении выдает SteamID. Примерно по такому принципу работает MA, как я понял
В таком случае статус отправляется только тогда, когда это нужно админу, а не каждые 5-15минут
 

iSe7en

Участник
Сообщения
209
Реакции
112
@Reiko1231, ну да, я так и сделал. Когда нажимаешь на Бан, то идет перенаправление и передает туда ник. В цикле сравниваеются два массива, в одном ники, во втором SteamID. При совпадении выдает SteamID. Примерно по такому принципу работает MA, как я понял
В таком случае статус отправляется только тогда, когда это нужно админу, а не каждые 5-15минут
Не сказал бы что это удачное решение, т.к читеры могут менять быстро ники, делать их пустыми, вставлять такие символы, что вывод в статусе съезжает на новую строку и прочие пакости
 
  • Мне нравится
Реакции: DOVE

SAPSAN 隼

Не было б печали, если бы ключи мне дали!
Сообщения
822
Реакции
778
@DOWE, посмотри у меня в Shop там есть пример для вывода и кеширования статуса онлайна для игроков
PHP:
public function OnlinePlayer($steam){
        $cacheFile = "cache/online.txt";
        $status = array(1 => 'offline', 2 => '<br><b style="color:#e42f2f">Нет на сервере</b>');
        if(!file_exists($cacheFile)){
            $this->cacheOnline();
            foreach ($this->readCacheOnline($cacheFile) as $key) {
                if($key == $steam){
                    $status = array(1 => 'online', 2 => '<br><b style="color:#368c36">Cейчас на сервере</b>');
                }
            }
        }else if(file_exists($cacheFile) && time() - 300 > filemtime($cacheFile)){
            unlink($cacheFile);
            $this->cacheOnline();
            foreach ($this->readCacheOnline($cacheFile) as $key) {
                if($key == $steam){
                    $status = array(1 => 'online', 2 => '<br><b style="color:#368c36">Cейчас на сервере</b>');
                }
            }
        }else {
            foreach ($this->readCacheOnline($cacheFile) as $key) {
                if($key == $steam){
                    $status = array(1 => 'online', 2 => '<br><b style="color:#368c36">Cейчас на сервере</b>');
                }
            }
        }

        return $status;
    }

    protected function cacheOnline(){
        if(!file_exists('cache'))
                mkdir('cache', 0777);
        $cacheFile = "cache/online.txt";
            $servers = Config::Servers();
         if(empty($servers['server'.$this->server]))
                 return false;
          $server = $servers['server'.$this->server];  
            $Query = new SourceQuery();
            try {  
                $Query->Connect($server['ip'], $server['port'], 2, SourceQuery::SOURCE);
                $Query->SetRconPassword($server['rcon']);
                    $act = trim($Query->Rcon('status') , "\t\n\r\0\x0B");
                     $act = preg_match_all('/STEAM_[0-1]:[0-1]:[0-9]{1,11}/', $act, $matches);
            }catch(Exception $e){
                echo '<script type="text/javascript">allert('.$e->GetMessage().')</script>';
            }finally{
                $Query->Disconnect();
            }
            $logFileHandle = fopen($cacheFile, 'a');        
            foreach ($matches as $key => $value){
                fwrite($logFileHandle, implode('.', $value));
            }
            fclose($logFileHandle);
    }

    protected function readCacheOnline($cacheFile){
            $handle = fopen($cacheFile, "r");
                while (!feof($handle)) {
                    $buffer = fgets($handle, 4096);
                }
            fclose($handle);
            $info = explode('.', $buffer);
            return $info;
    }
 
  • Мне нравится
Реакции: DOVE

DOVE

GLite Inc.
Сообщения
296
Реакции
54
@Se7en_RUS, ну по сути я могу зайти с другом, поставить себе в ник STEAM_1:0:123456789 и выйдет путаница. Я понимаю что я пишу на процедурном стиле и это не лучшее решение. Так что я пока оставлю так, спасибо)))
 
Сверху Снизу