[SQLite] Online Players

Сообщения
1,032
Реакции
828
Помог
10 раз(а)
Задача плагина независимо хранить различный тип онлайна игроков
  • Общий онлайн
  • Общий онлайн за исключением учета зрителей
  • Общий онлайн самой игры, то есть когда только живой

Далее по коду, как уже выяснилось, могут быть много нюансов, один из таких описан в соседней мною темой, когда вызывался spawn игрока при ClientPutInServer

Поэтому на всякий случай, спрошу еще об одном нюансе.
Можно ли как-то перейти в зрители, или, сменив команду минуя хук RG_CBasePlayer_Killed ?

C++:
#include < amxmodx >
#include < amxmisc >
#include < reapi >
#include < sqlx >

#pragma loadlib sqlite

#pragma semicolon 1

new const LOGS_FOLDER_NAME[ ]                =            "online_players";            // Наименование каталога ведение журналов
new const LOGS_FILE_NAME[ ]                    =            "online_players_error";        // Наименование журналов для ведение ошибочной информации

new const SQL_DATABASE[ ]                    =            "online_players";            // Наименование базы данных
new const SQL_TABLE[ ]                        =            "online_players";            // Наименование таблицы базы данных

const ELLIPSES_ARG                            =    4;
const RESET_VALUE                            =    0;

const MAX_LENGTH__PATH                        =    64;
const MAX_LENGTH__AUTHID                    =    64;
const MAX_LENGTH__SQL_QUERY                    =    1024;
const MAX_LENGTH__TIME                        =    32;
const MAX_LENGTH__MESSAGE                    =    512;

enum _: SQL_DATA_STRUCT
{
    SQL_DATA__QUERY_TYPE,
    SQL_DATA__PLAYER_USERID,
    SQL_DATA__PLAYER_AUTHID[ MAX_LENGTH__AUTHID ]
}

enum
{
    QUERY_TYPE__TABLE_CREATE,
    QUERY_TYPE__INSERT_ONLINE_PLAYER,
    QUERY_TYPE__GET_ONLINE_PLAYER,
    QUERY_TYPE__UPDATE_ONLINE_PLAYER
}

enum _: SQL_TABLE_COLUMNS_ENUM
{
    SQL_TABLE_COLUMN__PLAYER_AUTHID,
    SQL_TABLE_COLUMN__TOTAL_ONLINE_PLAYER,
    SQL_TABLE_COLUMN__GAMING_ONLINE_PLAYER,
    SQL_TABLE_COLUMN__LIVE_ONLINE_PLAYER
}

new const SQL_TABLE_COLUMNS[ SQL_TABLE_COLUMNS_ENUM ][ ] =
{
    "player_authid",
    "total_online_player",
    "gaming_online_player",
    "live_online_player"
};

new g_iPlGameTime;

new Handle: g_hSqlTuple;

new g_sLogsDir[ MAX_LENGTH__PATH ];
new g_sSqlQuery[ MAX_LENGTH__SQL_QUERY ];

new g_iPlTotalOnline[ MAX_PLAYERS + 1 ];
new g_iPlGamingOnline[ MAX_PLAYERS + 1 ];
new g_iPlLiveOnline[ MAX_PLAYERS + 1 ];

new g_iCachePlTotalOnline[ MAX_PLAYERS + 1 ];
new g_iCachePlGamingOnline[ MAX_PLAYERS + 1 ];
new g_iCachePlLiveOnline[ MAX_PLAYERS + 1 ];

new g_bAuthPlayer[ MAX_PLAYERS + 1 ];

new g_eSqlData[ SQL_DATA_STRUCT ];

new bool: g_bSpectator[ MAX_PLAYERS + 1 ];
new bool: g_bAlive[ MAX_PLAYERS + 1 ];

public plugin_init( )
{
    register_plugin( "Online Players", "1.0", "Javekson" );
   
    RegisterHookChain( RG_CBasePlayer_Spawn, "CBasePlayer_Spawn", .post = true );
    RegisterHookChain( RG_CBasePlayer_Killed, "CBasePlayer_Killed", .post = true );
    RegisterHookChain( RG_HandleMenu_ChooseTeam, "HandleMenu_ChooseTeam", .post = true );
    RegisterHookChain( RG_CBasePlayer_RoundRespawn, "CBasePlayer_RoundRespawn", .post = true );
}

public plugin_cfg( )
{
    get_localinfo( "amxx_logs", g_sLogsDir, charsmax( g_sLogsDir ) );
   
    formatex( g_sLogsDir, charsmax( g_sLogsDir ), "%s/%s", g_sLogsDir, LOGS_FOLDER_NAME );
   
    if( !dir_exists( g_sLogsDir ) )
    {
        mkdir( g_sLogsDir );
    }
   
    SQL_SetAffinity( "sqlite" );
   
    g_hSqlTuple = SQL_MakeDbTuple( "", "", "", SQL_DATABASE );
   
    func_SqlQueryTableCreate( );
}

public client_connect( id )
{
    g_bAuthPlayer[ id ] = false;
   
    g_bSpectator[ id ] = true;
   
    g_iPlTotalOnline[ id ] = RESET_VALUE;
    g_iPlGamingOnline[ id ] = RESET_VALUE;
    g_iPlLiveOnline[ id ] = RESET_VALUE;
   
    g_iCachePlTotalOnline[ id ] = RESET_VALUE;
    g_iCachePlGamingOnline[ id ] = RESET_VALUE;
    g_iCachePlLiveOnline[ id ] = RESET_VALUE;
}

public client_authorized( id, const sAuthID[ ] )
{
    if( is_user_bot( id ) || is_user_hltv( id ) )
    {
        return PLUGIN_CONTINUE;
    }
   
    g_bAuthPlayer[ id ] = true;
   
    func_SqlQueryGetOnlinePlayer( id, sAuthID );
   
    return PLUGIN_CONTINUE;
}

public client_disconnected( id )
{
    if( g_bAuthPlayer[ id ] )
    {
        g_iPlGameTime = get_user_time( id );
       
        /* ------------------------------ */
       
        g_iPlTotalOnline[ id ] += g_iPlGameTime - g_iCachePlTotalOnline[ id ];
       
        /* ------------------------------ */
       
        if( !g_bSpectator[ id ] )
        {
            g_iPlGamingOnline[ id ] += g_iPlGameTime - g_iCachePlGamingOnline[ id ];
        }
       
        /* ------------------------------ */
       
        if( g_bAlive[ id ] )
        {
            g_iPlLiveOnline[ id ] += get_user_time( id ) - g_iCachePlLiveOnline[ id ];
        }
       
        /* ------------------------------ */
       
        new sAuthID[ MAX_LENGTH__AUTHID ];
        get_user_authid( id, sAuthID, charsmax( sAuthID ) );
       
        func_SqlQueryUpdateOnlinePlayer( id, sAuthID );
    }
}

public CBasePlayer_Spawn( const id )
{
    if( is_user_alive( id ) )
    {
        g_iPlGameTime = get_user_time( id );
       
        /* ------------------------------ */
       
        if( g_bSpectator[ id ] )
        {
            g_bSpectator[ id ] = false;
           
            g_iCachePlGamingOnline[ id ] = g_iPlGameTime;
        }
       
        /* ------------------------------ */
       
        if( g_bAlive[ id ] )
        {
            g_iPlLiveOnline[ id ] += g_iPlGameTime - g_iCachePlLiveOnline[ id ];
        }
       
        g_iCachePlLiveOnline[ id ] = g_iPlGameTime;
       
        g_bAlive[ id ] = true;
    }
}

public CBasePlayer_Killed( id )
{
    g_bAlive[ id ] = false;
   
    g_iPlGameTime = get_user_time( id );
   
    g_iPlLiveOnline[ id ] += g_iPlGameTime - g_iCachePlLiveOnline[ id ];
   
    g_iCachePlLiveOnline[ id ] = g_iPlGameTime;
}

public CBasePlayer_RoundRespawn( const id )
{
    if( g_bAuthPlayer[ id ] )
    {
        g_iPlGameTime = get_user_time( id );
       
        /* ------------------------------ */
       
        g_iPlTotalOnline[ id ] += g_iPlGameTime - g_iCachePlTotalOnline[ id ];
       
        g_iCachePlTotalOnline[ id ] = g_iPlGameTime;
       
        /* ------------------------------ */
       
        g_iPlGamingOnline[ id ] += g_iPlGameTime - g_iCachePlGamingOnline[ id ];
       
        g_iCachePlGamingOnline[ id ] = g_iPlGameTime;
       
        /* ------------------------------ */
       
        new sAuthID[ MAX_LENGTH__AUTHID ];
        get_user_authid( id, sAuthID, charsmax( sAuthID ) );
       
        func_SqlQueryUpdateOnlinePlayer( id, sAuthID );
    }
}

public HandleMenu_ChooseTeam( const id, const MenuChooseTeam: iTeam )
{
    switch( iTeam )
    {
        case MenuChoose_Spec:
        {
            if( !g_bSpectator[ id ] )
            {
                g_iPlGamingOnline[ id ] += get_user_time( id ) - g_iCachePlGamingOnline[ id ];
               
                g_bSpectator[ id ] = true;
            }
        }
    }
}

func_SqlQueryTableCreate( )
{
    formatex( g_sSqlQuery, charsmax( g_sSqlQuery ),
        "CREATE TABLE IF NOT EXISTS `%s` ( \
        `%s` TEXT NOT NULL PRIMARY KEY ASC, \
        `%s` INTEGER NOT NULL, \
        `%s` INTEGER NOT NULL, \
        `%s` INTEGER NOT NULL )",
       
        SQL_TABLE,
       
        SQL_TABLE_COLUMNS[ SQL_TABLE_COLUMN__PLAYER_AUTHID ],
        SQL_TABLE_COLUMNS[ SQL_TABLE_COLUMN__TOTAL_ONLINE_PLAYER ],
        SQL_TABLE_COLUMNS[ SQL_TABLE_COLUMN__GAMING_ONLINE_PLAYER ],
        SQL_TABLE_COLUMNS[ SQL_TABLE_COLUMN__LIVE_ONLINE_PLAYER ]
    );
   
    func_MakeSqlQuery( QUERY_TYPE__TABLE_CREATE );
}

func_SqlQueryGetOnlinePlayer( const id, const sAuthID[ ] )
{
    formatex( g_sSqlQuery, charsmax( g_sSqlQuery ),
        "SELECT * FROM `%s` WHERE `%s` = '%s'",
        SQL_TABLE, SQL_TABLE_COLUMNS[ SQL_TABLE_COLUMN__PLAYER_AUTHID ], sAuthID
    );
   
    g_eSqlData[ SQL_DATA__PLAYER_USERID ] = get_user_userid( id );
   
    copy( g_eSqlData[ SQL_DATA__PLAYER_AUTHID ], charsmax( g_eSqlData[ SQL_DATA__PLAYER_AUTHID ] ), sAuthID );
   
    func_MakeSqlQuery( QUERY_TYPE__GET_ONLINE_PLAYER );
}

func_SqlQueryInsertOnlinePlayer( const id, const sAuthID[ ] )
{
    formatex( g_sSqlQuery, charsmax( g_sSqlQuery ),
        "INSERT INTO `%s` ( `%s`, `%s`, `%s`, `%s` ) \
        VALUES ( '%s', %d, %d, %d )",
       
        SQL_TABLE,
       
        SQL_TABLE_COLUMNS[ SQL_TABLE_COLUMN__PLAYER_AUTHID ],
        SQL_TABLE_COLUMNS[ SQL_TABLE_COLUMN__TOTAL_ONLINE_PLAYER ],
        SQL_TABLE_COLUMNS[ SQL_TABLE_COLUMN__GAMING_ONLINE_PLAYER ],
        SQL_TABLE_COLUMNS[ SQL_TABLE_COLUMN__LIVE_ONLINE_PLAYER ],
       
        sAuthID,
        g_iPlTotalOnline[ id ],
        g_iPlGamingOnline[ id ],
        g_iPlLiveOnline[ id ]
    );
   
    func_MakeSqlQuery( QUERY_TYPE__INSERT_ONLINE_PLAYER );
}

func_SqlQueryUpdateOnlinePlayer( const id, const sAuthID[ ] )
{
    formatex( g_sSqlQuery, charsmax( g_sSqlQuery ),
        "UPDATE `%s` SET `%s` = %d, `%s` = %d, `%s` = %d WHERE `%s` = '%s'",
       
        SQL_TABLE,
       
        SQL_TABLE_COLUMNS[ SQL_TABLE_COLUMN__TOTAL_ONLINE_PLAYER ],
        g_iPlTotalOnline[ id ],
       
        SQL_TABLE_COLUMNS[ SQL_TABLE_COLUMN__GAMING_ONLINE_PLAYER ],
        g_iPlGamingOnline[ id ],
       
        SQL_TABLE_COLUMNS[ SQL_TABLE_COLUMN__LIVE_ONLINE_PLAYER ],
        g_iPlLiveOnline[ id ],
       
        SQL_TABLE_COLUMNS[ SQL_TABLE_COLUMN__PLAYER_AUTHID ],
       
        sAuthID
    );
   
    func_MakeSqlQuery( QUERY_TYPE__UPDATE_ONLINE_PLAYER );
}

public handler_SqlQuery( iFailState, Handle: hQueryHandle, sError[ ], iErrorCode, eSqlData[ ], iDataSize, Float: fQueryTime )
{
    if( iFailState != TQUERY_SUCCESS )
    {
        SQL_GetQueryString( hQueryHandle, g_sSqlQuery, charsmax( g_sSqlQuery ) );
       
        func_Logging( g_sLogsDir, LOGS_FILE_NAME, "^"[SQL] Query error^"" );
        func_Logging( g_sLogsDir, LOGS_FILE_NAME, "^"[SQL] Error^" ^"#%d^", ^"%s^"", iErrorCode, sError );
        func_Logging( g_sLogsDir, LOGS_FILE_NAME, "^"[SQL] Query^" ^"%s^"", g_sSqlQuery );
       
        return PLUGIN_CONTINUE;
    }
   
    switch( eSqlData[ SQL_DATA__QUERY_TYPE ] )
    {
        case QUERY_TYPE__TABLE_CREATE:
        {
            return PLUGIN_CONTINUE;
        }
       
        case QUERY_TYPE__GET_ONLINE_PLAYER:
        {
            new iPlUserID = eSqlData[ SQL_DATA__PLAYER_USERID ];
           
            new iPlayerID = find_player_ex( FindPlayer_MatchUserId | FindPlayer_IncludeConnecting, iPlUserID );
           
            if( iPlayerID )
            {
                if( SQL_MoreResults( hQueryHandle ) )
                {
                    g_iPlTotalOnline[ iPlayerID ] = SQL_ReadResult( hQueryHandle, 1 );
                    g_iPlGamingOnline[ iPlayerID ] = SQL_ReadResult( hQueryHandle, 2 );
                    g_iPlLiveOnline[ iPlayerID ] = SQL_ReadResult( hQueryHandle, 3 );
                }
                else
                {
                    new sAuthID[ MAX_LENGTH__AUTHID ];
                    copy( sAuthID, charsmax( sAuthID ), eSqlData[ SQL_DATA__PLAYER_AUTHID ] );
                   
                    func_SqlQueryInsertOnlinePlayer( iPlayerID, sAuthID );
                }
            }
        }
       
        case QUERY_TYPE__INSERT_ONLINE_PLAYER:
        {
            return PLUGIN_CONTINUE;
        }
       
        case QUERY_TYPE__UPDATE_ONLINE_PLAYER:
        {
            return PLUGIN_CONTINUE;
        }
    }
   
    return PLUGIN_CONTINUE;
}

stock func_MakeSqlQuery( iQueryType )
{
    g_eSqlData[ SQL_DATA__QUERY_TYPE ] = iQueryType;
   
    SQL_ThreadQuery( g_hSqlTuple, "handler_SqlQuery", g_sSqlQuery, g_eSqlData, sizeof( g_eSqlData ) );
}

stock func_Logging( const sLogsDir[ ], const sFileName[ ], const sMessage[ ], any:... )
{
    new sFmtMsg[ MAX_LENGTH__MESSAGE ];
    vformat( sFmtMsg, charsmax( sFmtMsg ), sMessage, ELLIPSES_ARG );
   
    new sFileTime[ MAX_LENGTH__TIME ];
    get_time( "%m.%Y", sFileTime, charsmax( sFileTime ) );
   
    new sLogFile[ MAX_LENGTH__PATH + 32 ];
    formatex( sLogFile, charsmax( sLogFile ), "%s/%s_%s.log", sLogsDir, sFileName, sFileTime );
   
    new iFileID = fopen( sLogFile, "at" );
   
    new sRecordTime[ MAX_LENGTH__TIME ];
    get_time( "%d.%m.%Y - %H:%M:%S", sRecordTime, charsmax( sRecordTime ) );
   
    fprintf( iFileID, "^"%s^" %s^n", sRecordTime, sFmtMsg );
   
    fclose( iFileID );
}
 
Сообщения
1,698
Реакции
1,510
Помог
26 раз(а)
Можно ли как-то перейти в зрители, или, сменив команду минуя хук RG_CBasePlayer_Killed?
set_member(id, m_iTeam, TEAM_SPECTATOR);

Путин - дисконнект

Общий онлайн за исключением учета зрителей
HandleTeam - HandleTeam - дисконнект

Общий онлайн самой игры, то есть когда только живой
Спавн - Киллед / дисконнект
 
Сообщения
594
Реакции
350
Предупреждения
1
Помог
9 раз(а)
Добавь ещё последий заход на сервер ака последняя активность
 
Сообщения
1,032
Реакции
828
Помог
10 раз(а)
steelzzz, это вроде в любой статистике есть, а мне нужен независимый подсчет онлайна с API под другие плагины, в том числе и статистики =DD, статусов, званий и прочих приколюх
25 Янв 2020
set_member(id, m_iTeam, TEAM_SPECTATOR);
Я думал он визуально только перекидывает в спектры, ибо я помню приколюху, когда игрок был за спектров но бегал при этому и убивал всех )

Путин - дисконнект
Да, так и сделал, единственное еще в каждом раунде делаю сохранение, ну так, на всякий )

HandleTeam - HandleTeam - дисконнект
Я таким чудом могу набить онлайн себе, поэтому я чекаю спавн игрока еще после спектров к этой комбинации

Спавн - Киллед / дисконнект
Вот тут у меня и нюансы, ибо спавн можно вызывать повторно минуя килледа, точно так же уйти в спектры минуя килледа, нужно все это учитывать блин, ибо при спавне я делаю текущий кеш времени игрока, а при килледе я отнимаю от текущего времение тот самый кеш и получаю время онлайн живого игрока, но благодаря нюансам приходится что то придумывать и костылить =(
 
Сообщения
1,698
Реакции
1,510
Помог
26 раз(а)
Я думал он визуально только перекидывает в спектры, ибо я помню приколюху, когда игрок был за спектров но бегал при этому и убивал всех )
Мембер в памяти перекидывает. Для визуально - другим клиентам отправляется мессага TeamInfo.
 
Сообщения
1,032
Реакции
828
Помог
10 раз(а)
На всякий случай еще спрошу, как-то можно сменить команду миновав RG_HandleMenu_ChooseTeam ?
 
Сообщения
1,032
Реакции
828
Помог
10 раз(а)
fantom, скорее всего программно, юзер я так понимаю вряд ли сможет, речь о реализации плагина сейчас
 
Сообщения
1,032
Реакции
828
Помог
10 раз(а)
fantom, да, можно, уже проверил, значит RG_HandleMenu_ChooseTeam не подойдет что бы чекать переход в зрители
 
Сообщения
2,491
Реакции
2,794
Помог
61 раз(а)
Javekson, Если разговор о менюхе chooseteam или команде jointeam или кваре mp_auto_join_team, то тут все они срабатывают на RG_HandleMenu_ChooseTeam при условии: что никакой плагин не хукает и не переопределяет поведение. Все другие способы уже на программном уровне: туда входят rg_set_user_team, cs_set_user_team, set_member(id, m_iTeam) + message_begin TeamInfo. В 90% случаев достаточно хукнуть мессагу TeamInfo. Но это не 100% гарантия. А вот если тебе нужно хукнуть именно перевод в наблюдатели, то я бы выбрал метод с RG_CBasePlayer_StartObserver + проверкой на команду игрока (мертвый игрок также переходит в режим наблюдателя). Правда я не уверен сработает ли данный способ при cs_set_user_team без user_kill
 
Сообщения
1,032
Реакции
828
Помог
10 раз(а)
Правда я не уверен сработает ли данный способ при cs_set_user_team без user_kill
не сработает, проверил )
29 Янв 2020
fantom, мне по сути надо просто булевую переключить, что бы не учитывать онлайн спектра, но все ля можно обойти ) такой прикол в переходы в спектры я видел в деатране, когда наблюдатель просто бегал по карте, и при такой ситуации его онлайн будет чекаться )
 
Сообщения
1,032
Реакции
828
Помог
10 раз(а)
fantom, в общем в данной ситуации лучше TeamInfo чекать, предполагая, что никакой дурачек не будет менять команду не послав TeamInfo =D
Спасибо BlackSignature за разъяснение в личке
 
Сообщения
1,698
Реакции
1,510
Помог
26 раз(а)
@fantom, в общем в данной ситуации лучше TeamInfo чекать, предполагая, что никакой дурачек не будет менять команду не послав TeamInfo =D
Они так же могут послать ТеамИнфо не через emessage и тогда, твой хук не вызовется)
 
Сообщения
1,032
Реакции
828
Помог
10 раз(а)
fl0wer, вот че ты меня расстраиваешь:beee: и че же делать?
 
Сообщения
1,293
Реакции
2,295
Помог
57 раз(а)
и че же делать?
Делать так, как и делал, через TeamInfo. О чём ты вообще беспокоишься? О возможной несовместимости с другими плагинами? Это проблема уже тех, кто их юзает (косвенно, проблема авторов которые писали не думая о совместимости). Такое есть в старых плагинах, связанных с выбором/сменой команды. Там через fm ставится m_iTeam и отправляется TeamInfo, чаще всего не через emessage, да. Но сейчас в ходу реапи, и есть адекватный метод смены команды без шаманства и без подключения cstrike. Если человек до сих пор сидит на древних плагинах и не использует актуальный функционал - это его проблемы.
 
Сообщения
2,491
Реакции
2,794
Помог
61 раз(а)
В чем проблема подсчитать игроков во время запроса?
 

Пользователи, просматривающие эту тему

Сейчас на форуме нет ни одного пользователя.
Сверху Снизу