BLOG [WEB-BLOG] Просто о Ethernet`е

Сообщения
494
Реакции
340
Помог
11 раз(а)
Georg,
Переменная в enumeration CVAR_LIGHTING_NORMAL_ROUND у тебя в данном случае целочисленного типа, а должна быть строкой.
Функция bind_pcvar_string сразу запишет в переменную (в данном случае в CvarEffLighting[CVAR_LIGHTING_NORMAL_ROUND]) значение квара. При автоматическом создании конфига значение будет считываться с указанного в исходнике, в дальнейшем уже с самого конфига.

То есть значение это не надо получать через функцию get_pcvar_string, оно уже будет в переменной.
Проблема была в том, что при получении указателя указывается имя квара, а у тебя там было не понятно что вообще.
Не так:
get_cvar_pointer(CvarEffLighting[CVAR_LIGHTING_NORMAL_ROUND])
А вот так:
get_cvar_pointer("lighting_normal_round")
Это я просто указал на ошибку. Для работы с кварами типа bind_pcvar_* такая работа с кварами не имеет места быть.

Конечный вариант.
После старта сервера (через несколько секунд, когда вызовется форвард OnConfigsExecuted) выведется в консоль сервера значение квара.
Код:
#include <amxmodx>

enum CVARS{
    CVAR_LIGHTING_NORMAL_ROUND[8]
}

new CvarEffLighting[CVARS]

public plugin_init()
{
    bind_pcvar_string(
        create_cvar(
            "lighting_normal_round", "c", FCVAR_NONE,
            .description = "Map lighting [a-darkest // z-brightest // ''-default // 0-disabled]",
            .has_min = false, .min_val = 0.0,
            .has_max = false, .max_val = 0.0
        ), CvarEffLighting[CVAR_LIGHTING_NORMAL_ROUND], charsmax(CvarEffLighting[CVAR_LIGHTING_NORMAL_ROUND])
    );

    AutoExecConfig(true);
}

public OnConfigsExecuted()
{
    server_print("Cvar 'lighting_normal_round' = [%s]", CvarEffLighting[CVAR_LIGHTING_NORMAL_ROUND]);
}
 
Последнее редактирование:
Сообщения
65
Реакции
12
@bizon,Самое ясное объяснение, буду разбираться дальше.
Еще такой вопрос, возможно ли создать NPC который будет двигаться по карте (Имею ввиду без всяких залезаний на стену или провалы под текстуры). Знаю, что реализация идет в функции Think модуля Engine, вроде как register_think создает объект, но есть аналог на REAPI? Или лучше использовать Engine?
 
Сообщения
494
Реакции
340
Помог
11 раз(а)
Georg, чтобы объекту задавать некую интерполяцию движения - имитировать передвижение энтити через векторную скорость - нужно для начала задать нужный тип движения *movetype и плотность *_solid. Это касательно того, чтобы объект "не проваливался" "под текстуры" - движок будет учитывать коллизию других объектов с твоим объектом (если другие её поддерживают).
Все типы движения и плотность можно подглядеть в "hlsdk_const.inc".
Касательно того, чтобы не залезал на стену - нужно придумывать алгоритмы логики для непися, чтобы он учитывал различного рода препятствия.
На самом деле это не так просто, а если неписей будет еще и достаточно много, сложные алгоритмы могут дать просраться твоему процессору. Тут возможно стоит задуматься о том, чтобы делать всё это на уровне модулей, а не плагинов (обычные боты с их вэйпоинтами - яркий пример).

Такое понятие как "think" не привязано к какому-то определенному модулю вроде engine.
Если простыми словами "think" - функция (обработчик) какого-то определенного отрезка времени, когда нужно обработать какую-либо информацию относительно объекта.

Расписывать логику серьезного непися я не буду, да и вряд ли смогу.
Дам простой код для создания непися, который будет двигаться в сторону ближайшего игрока.

Код:
#include <amxmodx>
#include <fakemeta>
#include <reapi>
#include <xs>

public plugin_init()
{
    register_clcmd("npc_create", "@npc_create");
}

public plugin_precache()
{
    precache_model("models/npc/npc.mdl"); // моделька для непися
}

@npc_create(pPlayer)
{
    new
        eEnt,
        Float: fOrigin[3];

    @get_origin_aiming(pPlayer, fOrigin); // получаем координаты, куда смотрит игрок
    fOrigin[2] += 15.0; // чуть-чуть поднимем точку с координатами, чтобы не было застреваний (в идеале делать проверки через трэйсы)
    eEnt = rg_create_entity("info_target"); // создаем энтити

    engfunc(EngFunc_SetOrigin, eEnt, fOrigin); // устанавливаем координаты для объекта
    engfunc(EngFunc_SetModel, eEnt, "models/npc/npc.mdl"); // модель непися
    engfunc(EngFunc_SetSize, eEnt, Float: {-30.0, -30.0, 0.0}, Float: {30.0, 30.0, 0.0} ); // размеры непися

    set_entvar(eEnt, var_classname, "ent_npc"); // присваиваем класснэйм (для начала чтобы хотя бы отличить от других "info_target")
    set_entvar(eEnt, var_movetype, MOVETYPE_TOSS); // устанавливаем тип движения (гравитация, коллизия, прикосновение - полный фарш)
    set_entvar(eEnt, var_solid, SOLID_BBOX); // сделаем объект твёрдым (при SOLID_TRIGGER проваливаться сквозь "worldspawn" не будет - сквозь "текстуры")
    set_entvar(eEnt, var_nextthink, get_gametime() + 0.1); // вызываем следующую обработку "think'a" через get_gametime() - кол-во секунд, прошедшее со старта карты + 0.1

    SetThink(eEnt, "@think_npc"); // создаем обработчик "think" для нашего энтити-объекта
}

@think_npc(eEnt) //непосредственно сам обработчик "think'a"
{
    static
        iCountPlayers,
        pPlayers[MAX_PLAYERS],
        Float: fOriginNpc[3],
        Float: fOriginVictim[3],
        Float: fVelocity[3],
        Float: fAngles[3],
        Float: fMinDist,
        Float: fDist,
        pVictim;

    get_players(pPlayers, iCountPlayers, "ah"); // Получаем индексы всех игроков, кроме мёртвых и hltv

    if(iCountPlayers > 0) // если есть хотя бы 1 такой игрок (живой и не hltv)
    {
        get_entvar(eEnt, var_origin, fOriginNpc); // запишем координаты npc
        pVictim = NULLENT; // обнулим индекс жертвы
        fMinDist = 8192.0; // Сделаем дистанцию условно максимальной, чтобы найти хотя бы 1 минимальную дистанцию в цикле

        for(new i, pPlayer; i < iCountPlayers; i++) // пробегаемся циклом по всем полученными индексами игроков (живые и не hltv)
        {
            pPlayer = pPlayers[i]; // для удобочитаемости запишем в переменную индекс игрока

            get_entvar(pPlayer var_origin, fOriginVictim); // запишем координаты игрока

            fDist = get_distance_f(fOriginNpc, fOriginVictim); // запишем дистанцию между игроком и Npc
            if(fDist < fMinDist) // сравниваем таким образом дистанцию между нпс и каждым игроком
            {
                fMinDist = fDist; // если дистанция меньше, записываем её
                pVictim = pPlayer; // записываем индекс потенциальной жертвы
            }
        } // таким образом мы получаем индекс того игрока, кто ближе всего расположен к npc
   
        if(pVictim != NULLENT) // проверяем, что нашлась хотя бы 1 жертва (выше индекс мы обнуляли, на NULLENT и проверяем)
        {
            get_entvar(pVictim, var_origin, fOriginVictim); // запишем координаты жертвы

            xs_vec_sub(fOriginVictim, fOriginVictim, fVelocity); // из конечных координат вычитаем начальные, получаем векторную скорость для движения npc
            xs_vec_normalize(fVelocity, fVelocity); // нормализуем вектор
            xs_vec_mul_scalar(fVelocity, 300.0, fVelocity); // получаем условную привычную глазу скорость в 300 юнитов (очень сильно плюс-минус)

            vector_to_angle(fVelocity, fAngles); // переводим вектор в угол - получим направление поворота в сторону жертвы

            set_entvar(eEnt, var_velocity, fVelocity); // задаем скорость объекту, чтобы он двигался в направлении жертвы
            set_entvar(eEnt, var_angles, fAngles); // разворачиваем в сторону жертвы
        }
    }

    set_entvar(eEnt, var_nextthink, get_gametime() + 0.1); // вызываем следующий nextthink через 0.1
}

@get_origin_aiming(pPlayer, Float: fOriginEnd[3]) // возвращает координаты, куда смотрит игрок
{
    static Float: fOriginStart[3];

    get_entvar(pPlayer, var_origin, fOriginStart);
    get_entvar(pPlayer, var_view_ofs, fOriginEnd);

    xs_vec_add(fOriginStart, fOriginEnd, fOriginStart);

    get_entvar(pPlayer, var_v_angle, fOriginEnd);
    engfunc(EngFunc_MakeVectors, fOriginEnd);
    global_get(glb_v_forward, fOriginEnd);

    xs_vec_add_scaled(fOriginStart, fOriginEnd, 8192.0, fOriginEnd);

    engfunc(EngFunc_TraceLine, fOriginStart, fOriginEnd, IGNORE_MONSTERS, pPlayer, 0);
    get_tr2(0, TR_vecEndPos, fOriginEnd);
}
Это очень простой вариант. Нет никаких проверок на валидность, анимаций, проверок видит ли непись игрока.
Это просто пример.
Написал на коленке за 10 минут, не проверял. Возможны где-то косяки.

up. Поправил пару косяков в коде.
 
Последнее редактирование:
Сообщения
65
Реакции
12
bizon, Хорошо, пример очень хороший, попробую в тестах, что-то добавлю, выложу код позже.
Если такая чумовая нагрузка, что даже можно взорвать ядерный реактор, можно ли использовать невидимые блок-зоны и давать команду NPC на разворот? ну тип аналога WallGuard только для NPC. Не планируется, что NPC будет штук 20, максимум 5. Охота понять принцип живого объекта.
Кажется проще создать блок-схему алгоритма и учесть большую часть моментов. Попробую накидать и частями пробовать реализовать.
 
Сообщения
494
Реакции
340
Помог
11 раз(а)
Georg, если не делать какие-то серьёзные алгоритмы для условного поиска обходных путей через препятствия и им подобных, существенной нагрузки не будет.
Я делал как-то несколько npc как в сталкере (снорк, кровосос), которые вели себя адекватно (соответствующие движения под бег, ходьбу, атаку и прочее), но нападали на жертву только если она в зоне видимости, в остальное время они просто двигаются спокойно в случайные точки. Таких неписей спавнили на зм серверах (~200 примерно), нагрузки на процессор не наблюдалось, которую можно было бы заметить.
Если подходить к делу с умом и не быть великим макрооптимизатором, все будет нормально. Умеренная нагрузка не так страшна, как о ней пишут.
Касательно разворота, я выше показал как это сделать. Если речь идет о создании неких хитбоксов, привязанных к неписю, то я так полагаю, достаточно рассчитать угол для основного непися, а привязанные к нему хитбоксы разворачивать в зависимости от положения непися (ну и возможно от некоторых условий). В общем, не так все серьёзно.
Блок-схема алгоритма упрощает написание кода, но не учитывает обстоятельства и проблемы, которые вылезали, вылезают и будут вылезать. Красиво и хорошо это звучит в теории, о чем в принципе учат в институтах на первых же парах по программированию. Польза от этого есть, конечно, но многие забивают на такой подход в программировании, тем более когда речь идет о простых скриптах.
 
Сообщения
65
Реакции
12
bizon, 200 штук, даже тяжело представить, что творилось на сервере :scratch_one-s_head:
Значит можно не слишком заморачиваться и обойтись простыми вещами.
Никогда не понимал принцип преподавания в институтах, только одна теория и мало практики, да и та же ситуация стала в Тех.Колледжах.
И все таки остался у меня актуальный вопрос про разграничение ресурсов (К примеру по картам) или такая вещь фантазия как я понял?
11 Сен 2022
Начинаем API под UpdateClientData, пока что только так.
C++:
#include <amxmodx>
#include <reapi>

new g_WpnKeyCustom // В реализации, думаю, что передавать в натив (get - set)
#define CustomItem(%0) (get_entvar(%0, var_impulse) == g_WpnKeyCustom)

public plugin_init(){
    RegisterHookChain(RG_CBasePlayer_UpdateClientData, "HC_CBasePlayer_UpdateClientData");
}

// В реализации, разделение костюмных Key и стандартных, но чувствую, что даже тут пока что косяк есть
public HC_CBasePlayer_UpdateClientData(const this){
    static iItem = get_member(this, m_pActiveItem);
    if(iItem <= 0 || !CustomItem(iItem)){
        return HC_CONTINUE;
    }
    set_cd(CD_Handle, m_flNextAttack, get_gametime() + 0.001);
    return HC_SUPERCEDE;
}
В планах
  • Прорисовать пропавшие элементы (Декали, спрайты и т.д) без повтора кода.
  • Упросить Костюмные оружия
  • Понять принцип обмана клиент части
 
Сообщения
494
Реакции
340
Помог
11 раз(а)
Georg, штук 200 просто для теста того, как think для каждого непися будет влиять на нагрузку при таком количестве. Понятное дело, что это мясо, и так делать не стоит.
Не понял насчет разграничения ресурсов толком, а если понял верно, то нужно переписывать функционал анпрекешера.
Средствами плагинов вряд ли что-то можно сделать.
Для чего хук и обработка клиентдаты? Для замены звука выстрела?
 
Сообщения
65
Реакции
12
bizon, Да, я заметил, что звук выстрела невозможно заменить просто так, но видел способ через UpdateClientData, но с таким методом, пропадало все, т.е оружие становилась как палка в руках. Думаю, что такое API даст небольшую простоту, да и для себя почувствовать возможности AMXX.
Анпрекеш рассматривал как вариант, но модуль только под Пингвина написан, но думаю ради интереса не проблема развернуть сервер под Linux и поиграться с модулем.
 
Сообщения
494
Реакции
340
Помог
11 раз(а)
Georg, ну с условного 2014 года вроде как продвижений в плане замены звука выстрела нет. Ибо звук привязан к анимации модели и проигрывается на клиенте.
Примеры обработки клиентдаты вроде как можно поглядеть в пушках от корда (если нет чего-то актуальнее, конечно, я за темой оружий давно не следил, мэйби подскажут другие, кто в теме).
Из вариантов еще делать эмуляцию выстрела: блокировать сам выстрел, проигрывать нужную анимацию, звук, воссоздавать выстрел, плюс вручную придется делать обработку патронов при стрельбе (текущее кол-во и в запасе). Но честно нет уверенности в таком подходе. Не понятно насколько лучше будет такой подход визуально, в плане физики и нагрузки. Такой вариант юзали, когда вместо простого оружия был какой-нибудь арбалет/базука, например. То есть речи о дефолтной стрельбе там не было.
 
Сообщения
65
Реакции
12
bizon, Давно видел тему, что можно привязать свой звук к анимации, что если использовать такой метод и проигрывать звук через анимацию на сервере
 
Сообщения
494
Реакции
340
Помог
11 раз(а)
Georg, да вот только вроде как звук такой придётся редактировать в .qc файлике. А это вновь компиляция, и уже другая модель. Соответственно, придётся закачивать новую модельку клиенту.
Для каждого оружия это монотонная работа, это трата памяти, это лимиты 512.
 
Сообщения
3,331
Реакции
1,464
Помог
124 раз(а)
Сообщения
65
Реакции
12
Nordic Warrior, по описанию что-то перемешанное, но есть что посмотреть. Не сторонник json формата для таких целей. Либо просто я привык видеть JSON во всяких gulp только
 
Сообщения
494
Реакции
340
Помог
11 раз(а)
Nordic Warrior, в первом варианте нет замены звука выстрела, во втором - не допилен функционал, звука тоже нет (в качестве конфига фигурирует, не проигрывается, по заверениям юзеров).
 

d3m37r4

111111
Сообщения
1,425
Реакции
1,166
Помог
10 раз(а)
Блочишь дефолтный звук, засылаешь свой.
 
Сообщения
65
Реакции
12
bizon, d3m37r4,

C++:
#include <amxmodx>
#include <fakemeta>
#include <reapi>

new g_WpnKeyCustom
#define CustomItem(%0) (get_entvar(%0, var_impulse) == g_WpnKeyCustom)

public plugin_init(){
    register_forward(FM_UpdateClientData, "UpdateClientData", true);
}

public UpdateClientData(const pPlayer, const SendWeapons, const CD){
    static iItem; iItem = get_member(pPlayer, m_pActiveItem);
    if(iItem <= 0 || !CustomItem(iItem) || !CD || !is_user_alive(pPlayer)){
        return FMRES_IGNORED;
    }
    set_cd(CD, CD_flNextAttack, get_gametime() + 0.001);
    return FMRES_HANDLED;
}
Сделал, звук, спрайты и декали пропали как и должно быть.
Теперь буду пробовать прорисовать декали на карте, думаю, что лучше подгружать их из под карты.
 
Сообщения
579
Реакции
338
Предупреждения
1
Помог
9 раз(а)
Georg, ты занимаешься какой-то фигней, всё, что ты делаешь сейчас, уже сделано. Тебе уже сказали, посмотри как работают кастом оружия из ZP мода.
 
Сообщения
65
Реакции
12
steelzzz, Я делаю это для себя, листать готовый код тоже самое , что и заниматься копипастом без понимая
12 Сен 2022
steelzzz, и то, что я посмотрю в готовом решении, о том как это делают и т.д , пропадёт интерес в поисках каких-то функции в инклудах, никакого интереса не будет тестировать код и смотреть, что он выдаёт , поэтому я и спрашивал у bizon про NPC в сложности реализации и он показал, что не так сложно, главное разобраться, а не брать готовое и листать, с таким успехом можно было и готовых боссов под ZP посмотреть , которые неизвестно как сделаны на тот момент
 
Сообщения
453
Реакции
255
Помог
9 раз(а)
Georg, тебе советуют не с целью копипаста, а с целью понять где и как это используется.
 
Сообщения
65
Реакции
12
malniata, да я понял его мысль, но повторюсь, пропадает интерес к написанию и тестированию кода
 

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

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