Иконка ресурса

[VIP] Teammates Heal 2.0

1mpulse

node index.js
Сообщения
122
Реакции
165
Пользователь 1mpulse разместил новый ресурс:

[VIP] Teammates Heal - Добавляет возможность лечить союзников

Добавляет возможность лечить союзников, стреляя по союзникам, с включенной в вип функцией, вип игрок будет лечить.

Узнать больше об этом ресурсе...
--- Добавлено позже ---
Если у кого-то есть предложения что можно добавить, пишите.

Стоит ли добавить эффекты?
 
Последнее редактирование:

Kruzya

Участник
Сообщения
12,970
Реакции
10,914
  • Команда форума
  • #2
Немного критики, если позволите.

VIP_OnVIPLoaded() вызывается только один раз при старте ядра. При подгрузке модулей, он не вызывается, что вызывает некоторые возможные проблемы в работе модулей. Потому имеет смысл добавить OnPluginStart(), и ещё. При старте плагина, стоит так же хукнуть всех игроков, которые находятся на сервере. И необходимо делать анхук при выходе.
C-подобный:
public void OnPluginStart() {
    if (VIP_IsVIPLoaded())
        VIP_OnVIPLoaded();

    for (int iClient = 1; iClient <= MaxClients; iClient++) {
        if (IsClientInGame(iClient))
            OnClientPutInServer(iClient);
    }
}

public void OnClientDisconnect(int iClient) {
    SDKUnhook(iClient, SDKHook_OnTakeDamage, OnTakeDamage);
}

Далее...
C-подобный:
public void OnPluginEnd()
{
    VIP_UnregisterFeature(g_sFeature);
}
-->
C-подобный:
public void OnPluginEnd() {
    if ((CanTestFeatures() && GetFeatureStatus(FeatureType_Native, "VIP_UnregisterFeature") == FeatureStatus_Available) || LibraryExists("vip_core"))
        VIP_UnregisterFeature(g_sFeature);
}

C-подобный:
public Action OnTakeDamage(int iVictim, int &iAttacker, int &inflictor, float &damage, int &damagetype)
{
    if((IsValidPlayer(iVictim) && IsValidPlayer(iAttacker)) && (iVictim != iAttacker) && (GetClientTeam(iVictim) == GetClientTeam(iAttacker)))
    {
        if(VIP_IsClientVIP(iAttacker) && VIP_IsClientFeatureUse(iAttacker, g_sFeature))
        {
            int HP = GetClientHealth(iVictim);
            <...>
А не проще эти два условия объединить? По сути, выйдет то же самое.
Потому что если хотя бы одно выражение в условии не прошло валидность, то все дальнейшие сверки и вызовы функций в нём не выполняются.
C-подобный:
public Action OnTakeDamage(int iVictim, int &iAttacker, int &inflictor, float &damage, int &damagetype)
{
    if((IsValidPlayer(iVictim) && IsValidPlayer(iAttacker)) && (iVictim != iAttacker) && (GetClientTeam(iVictim) == GetClientTeam(iAttacker)) && VIP_IsClientVIP(iAttacker) && VIP_IsClientFeatureUse(iAttacker, g_sFeature))
    {
        int HP = GetClientHealth(iVictim);
        <...>

Следующий кусок вызывает немного негодования.
C-подобный:
KeyValues cfg;
int cfg_iHPH, cfg_iMH;

<...>

KFG_Load()
{
    if(cfg) delete cfg;
    cfg = new KeyValues("settings");
    if(!cfg.ImportFromFile("addons/sourcemod/data/vip/modules/teammates_heal.ini")) SetFailState("[VIP][Teammates Heal] - Файл конфигураций не найден");
    else
    {
        cfg.Rewind();
        cfg_iHPH = cfg.GetNum("hp_per_hit", 1);
        cfg_iMH = cfg.GetNum("max_hp", 100);
    }
}
1). Не совсем ясно, зачем хранить глобально KeyValues конфига, если с ним операции происходит один раз за всю карту? Лишняя трата памяти.
2). У некоторых SourceMod может стоять не в /addons/sourcemod/, а, скажем, в /addons/sourcemod_2/. Но путь к конфигу захардкожен. Будет ошибка.

C-подобный:
int cfg_iHPH, cfg_iMH;

<...>

KFG_Load() {
    char szPath[PLATFORM_MAX_PATH];
    BuildPath(Path_SM, szPath, sizeof(szPath), "data/vip/modules/teammates_heal.ini");

    KeyValues cfg = new KeyValues("settings");
    if (!cfg.ImportFromFile(szPath)) SetFailState("[VIP][Teammates Heal] - Файл конфигураций не найден");

    // пора бы запомнить, что SetFailState() так же блокирует выполнение всего дальнейшего кода. Он даже блокирует любое дальнейшее выполнение кода плагина. Потому смысл от else теряется.
    cfg.Rewind();
    cfg_iHPH = cfg.GetNum("hp_per_hit", 1);
    cfg_iMH = cfg.GetNum("max_hp", 100);
    delete cfg;
}
 

1mpulse

node index.js
Сообщения
122
Реакции
165
Немного критики, если позволите.

VIP_OnVIPLoaded() вызывается только один раз при старте ядра. При подгрузке модулей, он не вызывается, что вызывает некоторые возможные проблемы в работе модулей. Потому имеет смысл добавить OnPluginStart(), и ещё. При старте плагина, стоит так же хукнуть всех игроков, которые находятся на сервере. И необходимо делать анхук при выходе.
C-подобный:
public void OnPluginStart() {
    if (VIP_IsVIPLoaded())
        VIP_OnVIPLoaded();

    for (int iClient = 1; iClient <= MaxClients; iClient++) {
        if (IsClientInGame(iClient))
            OnClientPutInServer(iClient);
    }
}

public void OnClientDisconnect(int iClient) {
    SDKUnhook(iClient, SDKHook_OnTakeDamage, OnTakeDamage);
}

Далее...
C-подобный:
public void OnPluginEnd()
{
    VIP_UnregisterFeature(g_sFeature);
}
-->
C-подобный:
public void OnPluginEnd() {
    if ((CanTestFeatures() && GetFeatureStatus(FeatureType_Native, "VIP_UnregisterFeature") == FeatureStatus_Available) || LibraryExists("vip_core"))
        VIP_UnregisterFeature(g_sFeature);
}

C-подобный:
public Action OnTakeDamage(int iVictim, int &iAttacker, int &inflictor, float &damage, int &damagetype)
{
    if((IsValidPlayer(iVictim) && IsValidPlayer(iAttacker)) && (iVictim != iAttacker) && (GetClientTeam(iVictim) == GetClientTeam(iAttacker)))
    {
        if(VIP_IsClientVIP(iAttacker) && VIP_IsClientFeatureUse(iAttacker, g_sFeature))
        {
            int HP = GetClientHealth(iVictim);
            <...>
А не проще эти два условия объединить? По сути, выйдет то же самое.
Потому что если хотя бы одно выражение в условии не прошло валидность, то все дальнейшие сверки и вызовы функций в нём не выполняются.
C-подобный:
public Action OnTakeDamage(int iVictim, int &iAttacker, int &inflictor, float &damage, int &damagetype)
{
    if((IsValidPlayer(iVictim) && IsValidPlayer(iAttacker)) && (iVictim != iAttacker) && (GetClientTeam(iVictim) == GetClientTeam(iAttacker)) && VIP_IsClientVIP(iAttacker) && VIP_IsClientFeatureUse(iAttacker, g_sFeature))
    {
        int HP = GetClientHealth(iVictim);
        <...>

Следующий кусок вызывает немного негодования.
C-подобный:
KeyValues cfg;
int cfg_iHPH, cfg_iMH;

<...>

KFG_Load()
{
    if(cfg) delete cfg;
    cfg = new KeyValues("settings");
    if(!cfg.ImportFromFile("addons/sourcemod/data/vip/modules/teammates_heal.ini")) SetFailState("[VIP][Teammates Heal] - Файл конфигураций не найден");
    else
    {
        cfg.Rewind();
        cfg_iHPH = cfg.GetNum("hp_per_hit", 1);
        cfg_iMH = cfg.GetNum("max_hp", 100);
    }
}
1). Не совсем ясно, зачем хранить глобально KeyValues конфига, если с ним операции происходит один раз за всю карту? Лишняя трата памяти.
2). У некоторых SourceMod может стоять не в /addons/sourcemod/, а, скажем, в /addons/sourcemod_2/. Но путь к конфигу захардкожен. Будет ошибка.

C-подобный:
int cfg_iHPH, cfg_iMH;

<...>

KFG_Load() {
    char szPath[PLATFORM_MAX_PATH];
    BuildPath(Path_SM, szPath, sizeof(szPath), "data/vip/modules/teammates_heal.ini");

    KeyValues cfg = new KeyValues("settings");
    if (!cfg.ImportFromFile(szPath)) SetFailState("[VIP][Teammates Heal] - Файл конфигураций не найден");

    // пора бы запомнить, что SetFailState() так же блокирует выполнение всего дальнейшего кода. Он даже блокирует любое дальнейшее выполнение кода плагина. Потому смысл от else теряется.
    cfg.Rewind();
    cfg_iHPH = cfg.GetNum("hp_per_hit", 1);
    cfg_iMH = cfg.GetNum("max_hp", 100);
    delete cfg;
}
как лучше делать наверное тебе веднее, я делаю как мне удобно и как умею.
 

R1KO

fuck society
Сообщения
9,457
Реакции
7,786
  • Команда форума
  • #5

Amirsz

Релаксируем... Ну хотя бы пытаемся
Сообщения
261
Реакции
81
А удары ножом лечат?
 

SlavON

Добрая душа
Сообщения
1,582
Реакции
326
@Amirsz, самое прикольное что и тот же молотов массово лечит)
--- Добавлено позже ---
@1mpulse, всё таки в процентах от урона надо бы сделать или на выбор.
 

Kruzya

Участник
Сообщения
12,970
Реакции
10,914
  • Команда форума
  • #12
@SlavON, фича, не баг.
Даже гранаты по идее должны хилить. HE-шки которые.
 

Amirsz

Релаксируем... Ну хотя бы пытаемся
Сообщения
261
Реакции
81

Kruzya

Участник
Сообщения
12,970
Реакции
10,914
  • Команда форума
  • #14
@Amirsz, а тов. @SlavON предлагает в процентах указывать. Указал, например, 50, и граната, которая должна была нанести своему тиммейту 50 дмг, отхиливает его наоборот на 25 хп.
 

SlavON

Добрая душа
Сообщения
1,582
Реакции
326
@Kruzya, так я это и не воспринял как баг, наоборот крутяк)
 

1mpulse

node index.js
Сообщения
122
Реакции
165
@Amirsz, самое прикольное что и тот же молотов массово лечит)
--- Добавлено позже ---
@1mpulse, всё таки в процентах от урона надо бы сделать или на выбор.
добавлю в след версии, black list на какое оружие не будет работать модуль
--- Добавлено позже ---
@SlavON, я себе представляю это так:

- Пасаны, мало ХП, может кто Хаешку закинуть в тёмку?
*какой-то вип кидает*
- О, спасибо, братан!
это модуль сам по себе не заходит на паблик, так как в целом хил союзников на паблике, как минимум странно.
 

SlavON

Добрая душа
Сообщения
1,582
Реакции
326
это модуль сам по себе не заходит на паблик, так как в целом хил союзников на паблике, как минимум странно.
Как для массовой раздачи конечно, но как главному админу норм побаловаться))
 

Reiko1231

AlexTheRegent
Сообщения
508
Реакции
1,335
И необходимо делать анхук при выходе
Не нужно делать анхук при выходе. Расширение само снимает все хуки.
C-подобный:
void SDKHooks::OnClientDisconnecting(int client)
{
    CBaseEntity *pEntity = gamehelpers->ReferenceToEntity(client);
   
    HandleEntityDeleted(pEntity, client);
}

C-подобный:
void SDKHooks::HandleEntityDeleted(CBaseEntity *pEntity, int ref)
{
    // Send OnEntityDestroyed to SM listeners
    SourceHook::List<ISMEntityListener *>::iterator iter;
    ISMEntityListener *pListener = NULL;
    for (iter = m_EntListeners.begin(); iter != m_EntListeners.end(); iter++)
    {
        pListener = (*iter);
        pListener->OnEntityDestroyed(pEntity);
    }

    // Call OnEntityDestroyed forward
    g_pOnEntityDestroyed->PushCell(ref);
    g_pOnEntityDestroyed->Execute(NULL);

    Unhook(pEntity);

    m_EntityExists.Set(gamehelpers->ReferenceToIndex(ref), false);
}

C-подобный:
void SDKHooks::Unhook(CBaseEntity *pEntity)
{
    if (pEntity == NULL)
    {
        return;
    }

    int entity = gamehelpers->EntityToBCompatRef(pEntity);
    for (size_t type = 0; type < SDKHook_MAXHOOKS; ++type)
    {
        ke::Vector<CVTableList *> &vtablehooklist = g_HookList[type];
        for (size_t listentry = 0; listentry < vtablehooklist.length(); ++listentry)
        {
            ke::Vector<HookList> &pawnhooks = vtablehooklist[listentry]->hooks;
            for (size_t entry = 0; entry < pawnhooks.length(); ++entry)
            {
                if (entity != pawnhooks[entry].entity)
                {
                    continue;
                }

                pawnhooks.remove(entry--);
            }

            if (pawnhooks.length() == 0)
            {
                delete vtablehooklist[listentry];
                vtablehooklist.remove(listentry--);
            }
        }
    }
}
 
Сверху Снизу