Обучение и помощь по скриптингу для MIRDOBRO777

Сообщения
111
Реакции
26
d3m37r4, спасибо за пояснение, но урон блокируется в любом случае, т.е. при любом значении SetHookChainReturn(ATYPE_INTEGER, 1);. А можно сделать, чтобы урон проходил, при блокировке всех выполняемых ниже функциях?
Вот полная картина кода:
Код:
public player_damage_pre(id, iWeapon, iAttacker, Float:fDamage, iType) {
    if(is_user_alive(iAttacker) && iAttacker != id && get_member(iAttacker, m_iTeam) == CS_TEAM_CT && get_user_weapon(iAttacker) == CSW_KNIFE && iType == (DMG_BULLET|DMG_NEVERGIB) && DMG_FALL) {
    g_bStrike[iAttacker] = true;
    g_flBlockDamageTime[iAttacker] = 0.0;
    SetHookChainReturn(ATYPE_INTEGER, 1);
    return HC_SUPERCEDE;
}

    if(g_bDuel) {
    функция, когда дуэль;
    return HC_CONTINUE;
}

    return HC_CONTINUE;
}
В любом случае, при совпадении всех условий, урон блокируется. А как сделать, чтобы при совпадении условий, например, проверка на переменную включения плагина, урон проходил, но все функции, идущие далее после включения/отключения, блокировались?
Вот еще пример:
Код:
public форвард_пре_урона() {
    if(проверка на включение плагина( {
    блокируем выполнение дальнейших функций}
}

    if(проверка любая( {
    функция не должна работать, если выше заблокировано
}

    урон проходит в любом случае
}
 
Сообщения
1,175
Реакции
2,144
Помог
57 раз(а)
MIRDOBRO777, так return в данном случае заканчивает выполнение функции. Код ниже не будет вызван.
 
Сообщения
111
Реакции
26
Здоровья, форумчане!
Меня снова терзают несколько вопросов.
1. Можно ли заменить функцию " set_user_godmode(player, true);" на альтернативу ReAPI (не хочется подключать целый мод из-за одной функции)?
2. Как отследить время раунда? Например, когда остается минута и менее до конца раунда, то блокируется открытие определенного меню.
3. Возможно ли полностью очистить таблицу в SQLite, не удаляя ее?
 

d3m37r4

111111
Сообщения
1,420
Реакции
1,162
Помог
10 раз(а)
MIRDOBRO777, по поводу первого, Вактинча начинал писать сток функции с использованием реапи, там точно это есть:
По второму, в реапи есть мембер, который время раунда вроде возвращает, в противном случае можно использовать мембер старта раунда и из текущего времени его вычитать, получая оставшееся время.
30 Окт 2020
Для очистки таблицы можно truncate использовать.
 
Сообщения
1,175
Реакции
2,144
Помог
57 раз(а)
1) Код Вактинчи про который упоминал Дима
Код:
stock rg_set_user_taketamage(const player, bool:take) {
    set_entvar(player, var_takedamage, take ? DAMAGE_AIM : DAMAGE_NO)
}
3)
Код:
DELETE FROM `имя_таблицы`
 
Сообщения
111
Реакции
26
Всем здравия!
Ребята, прошу, кто опытен в скриптинге и есть желание подсказать, поправьте мой код, пожалуйста.
Обратите внимание на то, в чем можно сделать иначе или может где-то я допустил ошибки.
Лучше всего учиться на своем коде, поэтому и обращаюсь к опытным ребятам.
Суть плагина заключается в том, что он собирает топ самых играемых карт сервера. Карт конечно в БД может быть сколько угодно, но я вывожу в логи только ТОП-10. Вместо логов планирую сделать MOTD-окно.
Спасибо всем за предыдущие подсказки и за критику в данном плагине.
Код:
#pragma semicolon 1

#include <amxmodx>
#include <amxmisc>
#include <reapi>
#include <sqlx>

new g_iStartTime, g_iMapTime, /*g_iNumPlayers,*/ g_szMapName[64], g_iMapGames, g_iTotalTime, g_szLastDate[32];
new Handle:sql;
new const db_name[] = "popular_maps";
new const table_maps[] = "maps_data";
#define MAX_QUERY_LENGTH 1024

enum _:TOTAL_SQL_TYPES {
    SQL_TYPE_IGNORE,
    SQL_TYPE_MAPDATA,
    SQL_TYPE_MAPSTOP
};

public plugin_init() {
    register_plugin("Popular Maps", "1.0", "MirDobro777");

    RegisterHookChain(RG_CBasePlayer_Spawn, "on_player_spawn_post", .post = true);
    RegisterHookChain(RG_CSGameRules_RestartRound, "on_restart_round_pre", .post = false);

    g_iStartTime = get_systime();
    get_mapname(g_szMapName, charsmax(g_szMapName));
    set_task(12.0, "CheckMap");
}

public on_restart_round_pre() {
    if(get_member_game(m_bCompleteReset) && g_iMapTime < 1200) {
    g_iStartTime = get_systime();
}
}

public on_player_spawn_post(id) {
    g_iMapTime = get_systime() - g_iStartTime;
}

public OnConfigsExecuted() {
    SQL_SetAffinity("sqlite");
    sql = SQL_MakeDbTuple("", "", "", db_name); // Создание картежа данных для соединения с БД
    SQL_SetCharset(sql, "utf8");

// запрос на создание таблицы
    new szQuery[MAX_QUERY_LENGTH], szData[1] = SQL_TYPE_IGNORE;

    formatex(szQuery, charsmax(szQuery), "CREATE TABLE IF NOT EXISTS `%s` (\
    `mapname` TEXT NOT NULL,\
    `mapgames` INTEGER NOT NULL DEFAULT 0,\
    `maptime` INTEGER NOT NULL DEFAULT 0,\
    `maplast` TEXT NOT NULL,\
    PRIMARY KEY (mapname))", table_maps);
    SQL_ThreadQuery(sql, "Sql_Handler", szQuery, szData, sizeof szData);
}

public CheckMap() {
    new szQuery[MAX_QUERY_LENGTH], szData[1] = SQL_TYPE_MAPDATA;
    
    formatex(szQuery, charsmax(szQuery), "SELECT * FROM `%s` WHERE `mapname` = '%s'", table_maps, g_szMapName);
    SQL_ThreadQuery(sql, "Sql_Handler", szQuery, szData, sizeof szData);
}

public TopMapsGame() {
    new szQuery[256], szData[1];
    formatex(szQuery, charsmax(szQuery),"\
    SELECT * FROM %s WHERE `mapgames` > 0 ORDER BY `mapgames` DESC LIMIT 10\
    ", table_maps);

    szData[0] = SQL_TYPE_MAPSTOP;
//    szData[1] = id;
    SQL_ThreadQuery(sql, "Sql_Handler", szQuery, szData, sizeof szData);    

    return PLUGIN_HANDLED;
}

public UpdateMapGames() {
    new szQuery[MAX_QUERY_LENGTH], szData[1] = SQL_TYPE_IGNORE;
    formatex(szQuery, charsmax(szQuery),"\
    UPDATE `%s` SET\
    `mapgames` = '%d',\
    `maptime` = '%d',\
    `maplast` = '%s'\
    WHERE `mapname` = '%s'\
    ", table_maps, g_iMapGames, g_iTotalTime, g_szLastDate, g_szMapName);
    SQL_ThreadQuery(sql, "Sql_Handler", szQuery, szData, sizeof szData);
}

public Sql_Handler(iFailState, Handle:Query, szError[], iErrNum, szData[], size, Float:flQueryTime) {
    switch(iFailState) {
    case TQUERY_CONNECT_FAILED: {
    log_to_file("fail_sql.txt" , "^nConnection failed^nError: #%d^n%s^n", iErrNum, szError);
    return;
}
    case TQUERY_QUERY_FAILED: {
    log_to_file("fail_sql.txt" , "^nQuery failed^nError: #%d^n%s", iErrNum, szError);
    new szLastQuery[96];
    SQL_GetQueryString(Query, szLastQuery, charsmax(szLastQuery));
    log_to_file("fail_sql.txt", "^nLast Query: %s^n", szLastQuery);
    return;
}
}
    
    new iDataType = szData[0];
    switch(iDataType) {
    case SQL_TYPE_MAPDATA: {
    if(!SQL_NumResults(Query)) {
    new szQuery[MAX_QUERY_LENGTH], szData[1] = SQL_TYPE_IGNORE;
    formatex(szQuery, charsmax(szQuery), "INSERT INTO `%s` (`mapname`, `mapgames`, `maptime`, `maplast`)\
    VALUES ('%s', '0', '0', '0')\
    ", table_maps, g_szMapName);
    SQL_ThreadQuery(sql, "Sql_Handler", szQuery, szData, sizeof szData);
    } else {
    g_iMapGames = SQL_ReadResult(Query, SQL_FieldNameToNum(Query, "mapgames"));
    g_iTotalTime = SQL_ReadResult(Query, SQL_FieldNameToNum(Query, "maptime"));
    SQL_ReadResult(Query, SQL_FieldNameToNum(Query, "maplast"), g_szLastDate, charsmax(g_szLastDate));
    TopMapsGame();
}
}
    case SQL_TYPE_MAPSTOP: {
    new iNum, szMapName[64], iGames, iTime, szTime[32], szLast[32];

    while(SQL_MoreResults(Query)) {
    iNum++;
                
    SQL_ReadResult(Query, SQL_FieldNameToNum(Query, "mapname"), szMapName, charsmax(szMapName));
    iGames = SQL_ReadResult(Query, SQL_FieldNameToNum(Query, "mapgames"));
    iTime = SQL_ReadResult(Query, SQL_FieldNameToNum(Query, "maptime"));
    SQL_ReadResult(Query, SQL_FieldNameToNum(Query, "maplast"), szLast, charsmax(szLast));
    total_time(szTime, charsmax(szTime), iTime);

    log_to_file("top_maps.txt", "^n%d., %s^nИгр: %d^nВсего: %s^nДата: %s^n", iNum, szMapName, iGames, szTime, szLast);
    SQL_NextRow(Query);
}

}
}
}

public plugin_end() {
    if(g_iMapTime >= 1200) {
    g_iMapGames++;
    g_iTotalTime += g_iMapTime;
    last_date(get_systime());

    UpdateMapGames();
}
}

total_time(szTime[], iLen, iTime) {
    new iD, iH, iM;
    iD = iTime / 86400;
    iH = (iTime - iD * 86400) / 3600;
    iM = (iTime - iD * 86400 - iH * 3600) / 60;
    formatex(szTime, iLen, "%d д. %d ч. %d м.", iD, iH, iM);
}

last_date(iTime) {
    new szDate[32], szDay[3];
    format_time(szDate, charsmax(szDate), "%d.%m.%Y - %H:%M:%S", iTime);
    format_time(szDay, charsmax(szDay), "%w", iTime);

    if(equal(szDay, "0")) formatex(g_szLastDate, charsmax(g_szLastDate), "%s, Вс", szDate);
    else if(equal(szDay, "1")) formatex(g_szLastDate, charsmax(g_szLastDate), "%s, Пн", szDate);
    else if(equal(szDay, "2")) formatex(g_szLastDate, charsmax(g_szLastDate), "%s, Вт", szDate);
    else if(equal(szDay, "3")) formatex(g_szLastDate, charsmax(g_szLastDate), "%s, Ср", szDate);
    else if(equal(szDay, "4")) formatex(g_szLastDate, charsmax(g_szLastDate), "%s, Чт", szDate);
    else if(equal(szDay, "5")) formatex(g_szLastDate, charsmax(g_szLastDate), "%s, Пт", szDate);
    else if(equal(szDay, "6")) formatex(g_szLastDate, charsmax(g_szLastDate), "%s, Сб", szDate);
}
 
Сообщения
645
Реакции
222
Помог
11 раз(а)
MIRDOBRO777,
Код:
public on_player_spawn_post(id) {
    g_iMapTime = get_systime() - g_iStartTime;
}
если на сервере фулл игроки, то вызывается 32 раза и 32 раза будет вычитывается время карты (повторение), замени хук, лучше просто в plugin_end() вычесть и полученное число прибавить в g_iTotalTime

g_iTotalTime += (get_systime() - g_iStartTime)
 
Последнее редактирование:
Сообщения
111
Реакции
26
Limbooc, ты подкинул мне идею учитывать онлайн на карте, чтобы не добавлять в БД карты, где никто не играл.
Вот такая идея в коде:
Код:
public on_player_spawn_post(id) {
    new players[MAX_PLAYERS],pnum;
    get_players(players, pnum, "ach");
    g_iNumPlayers = pnum;

    if(g_iNumPlayers >= 2 && g_iStartTime != get_systime()) {
    if(g_iStartTime > 0) {
    g_iTempTime = get_systime() - g_iStartTime;
    g_iStartTime = get_systime();
    } else g_iStartTime = get_systime();

    g_iMapTime += g_iTempTime;
    log_to_file("respawn_player.txt" , "^nStart: %d^nTemp: %d^nMap: %d^n", g_iStartTime, g_iTempTime, g_iMapTime);
}
}
Событие рестарта и раунда не учитываю, подсчет ведется исключительно игрового времени с игроками.
 
Сообщения
1,012
Реакции
814
Помог
10 раз(а)
MIRDOBRO777, мне кажется ты перемудрил сильно с этим плагином, вопрос, тебе это надо только для себя, в логах/мотд? То есть не надо куда на сайт выводить этот топ? Просто если нет, то зачем вообще эта база нужна тебе?
 
Сообщения
111
Реакции
26
Javekson, чегоперемудрил? Я еще дописываю рейтинг карт сюда же в код. Сюда обратился за подсказками матерых скриптеров, но никто ничего не говорит. Как я понял, что по коду вроде у меня не совсем так уж плохо. На сайт не надо, только на сервере MOTD. А как еще хранить такой объем информации, включая рейтинг карт, где еще и база с проголосовавшими игроками и их оценками?
 
Сообщения
451
Реакции
254
Помог
9 раз(а)
MIRDOBRO777, если тупо для мотд - можно даже нваулт заюзать наверное, либо в .ini файликах хранить
 
Сообщения
1,012
Реакции
814
Помог
10 раз(а)
MIRDOBRO777, тогда ты не правильно описал задачу, изначально ты сказал что тебе просто нужен топ10 карт, для этой цели целиком базу юзать не нужно, достаточно будет файла. В плугине_энд проверять какая карта, сколько на ней отыграли, были ли на этой карте игроки и все, не надо тебе не рестартов раунда, не спавнов и прочего. Парсишь файл и плюсуешь карте+1 если подходит требованием. Для мотд достаточно снова спарсить файл в массив, осортировать его и вывести первые 10 карт. По изначально описанной тобою задачей этого вполне достаточно.
17 Май 2022
MIRDOBRO777, ну можно массив держать открытым всю карту, тогда каждый раз парсить не придется при вызове мотд
17 Май 2022
но никто ничего не говорит.
потому что как правило забивают большой и толстый, особенно когда код больше 50 строчек
17 Май 2022
где еще и база с проголосовавшими игроками и их оценками?
подробнее опиши всю задачу целиком, юзать базу где попало, не стоит, мое мнение, не вижу смысла, особенно когда объем данных не превышает в твоем случае кол-во карт, не думаю что даже сотня есть.
 
Последнее редактирование модератором:
Сообщения
111
Реакции
26
Javekson,

Есть порожденные твоими подсказками дополнительные вопросы:
1. как проверять были ли игроки на карте? Если были, то нужно вести учет сыгранного времени только с игроками, а это как проверять, чтобы не записывать время пустой карты?
Например, на карте играют 4 человека, они отыграли на ней 15 минут, после чего оставшееся время до смены играет только один. В хранилище я хочу записывать время с игроками не менее 20 минут. Даже если карта не сменится и один, который остался на карте, дождется других, то к предыдущим 15 минутам надо будет плюсовать новое время, но когда стало минимум 2 игрока.
2. Парсить данные в массив, когда они уже отсортированы, я умею. А если записывать данные карты в файл, то как их сортировать по ТОП?
Например, содержимое файла:
Код:
cs_assault 1
de_dust2_2x210
de_nuke 5
de_train 3
de_dust2 7
de_dust 2
Как из этого файла формировать ТОП?
Описание задачи:
1. Сбор данных о количестве сыгранного времени, число игр, последняя дата игры на той или иной карте и рейтинг, который высчитывается как среднее арифметическое.
2. Хранить надо, если брать БД:
а) таблица в БД со всеми картами, которые есть на сервере со столбцами: карта, число игр, отыгранный онлайн, сумма оценок игроков, число голосов и дата последней игры
б) таблицы с названием каждой карты с содержимым: ник игрока, его ID, оценка карте, дата оценки и личное время игры на той или иной карте
Вроде бы ничего не забыл.
Спасибо, что откликнулся. Понимаю, что вопросы глуповаты и разбираться в коде тоже запарно.
Благодарен всем, кто помогал! Много чего уже знаю :)
 
Сообщения
1,012
Реакции
814
Помог
10 раз(а)
MIRDOBRO777, да, для этой задачи уже будет целесообразней юзать бд
18 Май 2022
1. как проверять были ли игроки на карте?
секундный таск ))) в нем проверишь играют ли игроки по обе команды, заодно плюсанешь время как карте так и каждому игроку исключая спектров
18 Май 2022
Как из этого файла формировать ТОП?
ты же сказал умеешь сортировать массивы, загони в массив файл и отсортируй, по новой выведишь первые 10 индексов
18 Май 2022
а) таблица в БД со всеми картами, которые есть на сервере со столбцами: карта, число игр, отыгранный онлайн, сумма оценок игроков, число голосов и дата последней игры
б) таблицы с названием каждой карты с содержимым: ник игрока, его ID, оценка карте, дата оценки и личное время игры на той или иной карте
Вроде бы ничего не забыл.
делай многие ко многим, у тебя будет три таблицы, 1 таблица карт, 2 таблица игроки, 3 таблицы связь между этими двумя таблицами
то есть 3-я таблица у тебя будет содержать id игрока из 2-ой таблицы и id карты из 1-ой таблицы, где и укажешь время игры на этой карте, кол-во голосов, дата первого и последнего голоса.

Потом запросами просто будешь объединять эти таблицы и выводить что угодно, общее время игры игрока, или время игрока по каждой карте, или совокупное или среднее время игры на этой карте, среднее кол-во онлайна, общее кол-во голосов игрока или отдельно по каждой карте, общее гол-во голосов самой карты или отдельно по каждому игроку с датами последних голосов. В общем все что душе станет угодно
18 Май 2022
@MIRDOBRO777,а потом всего этого тебе покажется мало и ты захочешь вот это
Opera Снимок_2022-05-18_162141_stalin-volki.ru.png
поэтому не парь себе мозги, юзай готовые инструменты ыЫ
 

Вложения

Сообщения
111
Реакции
26
Javekson,

Я говорил, что умею заносить уже готовые данные в динамический массив, а вот если в него заносить просто подряд строки, то как их сортировать в самом массиве по принципу от больших значений к меньшим, вот это не знаю как делать.
На счет скринов... Я незрячий и не могу, соответственно, увидеть содержимое скринов.
А чем принцип трех таблиц лучше, чем на каждую карту своя?
БД будет в таком случае шустрее?
 
Сообщения
1,012
Реакции
814
Помог
10 раз(а)
MIRDOBRO777, ну как один из вариантов сортировки с использование структуры массива
C++:
#include < amxmodx >

enum _:STRUCT {
    MAP[ 32 ],
    COUNT
}

new const MAPS[ ][ STRUCT ] = {
    {    "cs_assault",    5    },
    {    "de_dust2_2x2",    10    },
    {    "de_nuke",        5    },
    {    "de_train",        3    },
    {    "de_dust2",        7    },
};

new Array:g_aMaps;
new g_eMapsData[ STRUCT ];

public plugin_init( ) {
    g_aMaps = ArrayCreate( STRUCT );
    
    for( new i; i < sizeof( MAPS ); i++ )
    {
        copy( g_eMapsData[ MAP ], charsmax( g_eMapsData[ MAP ] ), MAPS[ i ][ MAP ] );
        g_eMapsData[ COUNT ] = MAPS[ i ][ COUNT ];
        
        ArrayPushArray( g_aMaps, g_eMapsData );
    }
    
    ArraySort( g_aMaps, "callback_arraysort" );
}

public callback_arraysort( Array:array, elem1, elem2 )
{
    new data1[ STRUCT ];
    ArrayGetArray( array, elem1, data1 );
    
    new data2[ STRUCT ];
    ArrayGetArray( array, elem2, data2 );
    
    if( data1[ COUNT ] > data2[ COUNT ] ) {
        return -1;
    } else if( data1[ COUNT ] < data2[ COUNT ] ) {
        return 1;
    } else {
        return 0;
    }
}
на выходе получишь
de_dust2_2x2: 10
de_dust2: 7
de_nuke: 5
cs_assault: 5
de_train: 3
Иначе говоря при старте карты 1 раз отсортировал, потом все время юзаешь открытый уже отсортированный массив данных
18 Май 2022
А чем принцип трех таблиц лучше, чем на каждую карту своя?
ты хочешь создать 50 таблиц?) Наверное лучше 3 таблицы чем 50?
 

d3m37r4

111111
Сообщения
1,420
Реакции
1,162
Помог
10 раз(а)
А чем принцип трех таблиц лучше, чем на каждую карту своя?
Неверное проектирование структуры БД в дальнейшем больше проблем принесет.
Реляционные БД, которые упоминал Javekson, как раз таки и нужны для организации нормальной и точной структуры для быстрой работы с внесенными данными.

P.S. Сортировать можно и в mysql при запросе данных. Пример: тык.
 

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

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