Контакты (заказать плагин/исправить ошибки/другое) Поиск

[ вход ]
[ последние сообщения ]

  • Страница 1 из 1
  • 1
OnLibraryAdded / OnLibraryRemoved
_wS_ Дата: Понедельник, 06.04.2026, 14:19:48 | Сообщение # 1
OnLibraryAdded / OnLibraryRemoved

Не думал, что они реализованы так плохо.
Если w1.smx, w2.smx, w3.smx делают RegPluginLibrary("L"), то результат:

Код
// LOAD

] sm plugins load w1.smx
[w1.smx] OnLibraryAdded 'L'

] sm plugins load w2.smx
[w1.smx] OnLibraryAdded 'L'
[w2.smx] OnLibraryAdded 'L'
[w2.smx] OnLibraryAdded 'L'

] sm plugins load w3.smx
[w1.smx] OnLibraryAdded 'L'
[w2.smx] OnLibraryAdded 'L'
[w3.smx] OnLibraryAdded 'L'
[w3.smx] OnLibraryAdded 'L'
[w3.smx] OnLibraryAdded 'L'

// UNLOAD

] sm plugins unload w3.smx
[w1.smx] OnLibraryRemoved 'L' exists: 1
[w2.smx] OnLibraryRemoved 'L' exists: 1
[w3.smx] OnLibraryRemoved 'L' exists: 1

] sm plugins unload w2.smx
[w1.smx] OnLibraryRemoved 'L' exists: 1
[w2.smx] OnLibraryRemoved 'L' exists: 1

] sm plugins unload w1.smx
[w1.smx] OnLibraryRemoved 'L' exists: 0


Один плагин может зарегистрировать кучу библиотек с одинаковым именем. Если учесть, что библиотеки регистрируют и расширения, то в итоге можно легко нарваться на конфликт. Если вы делаете, например, какие-то хуки внутри OnLibraryAdded и удаляете их в OnLibraryRemoved, то т.к. SM не заботится о дубликатах, ваш хук вызовется 'x' раз подряд.

Получается, нужно делать что-то вроде такого для безопасности:

Код
int g_Library_L = 0;

public void OnLibraryAdded(const char[] name) {
    if (strcmp(name, "L") == 0 && ++g_Library_L == 1) {
        // Библиотека добавлена впервые.
    }
}

public void OnLibraryRemoved(const char[] name) {
    if (strcmp(name, "L") == 0 && g_Library_L > 0 && --g_Library_L == 0) {
        // Библиотека удалена (копий нет).
    }
}
 
TXCodding Дата: Пятница, 08.05.2026, 21:26:49 | Сообщение # 2
Сообщений: 5
Репутация: 0 [ +/- ]
А как же Reference Counting?
Вместо глобальных переменных система, которая сама считает ссылки. В SourceMod autoexecconfig.inc
Создаем хранилище счетчиков
Глобальный StringMap, который хранит, сколько раз была зарегистрирована каждая библиотека.
Код
static StringMap g_hLibReferences;

public void OnPluginStart()
{
    g_hLibReferences = new StringMap();
}

Гибкий обработчик событий
Код
void OnLibraryChange(const char[] name, bool bAdded)
{
    int iRefCount;
    
    if (bAdded)
    {
        // Пытаемся получить текущий счетчик
        if (g_hLibReferences.GetValue(name, iRefCount))
        {
            iRefCount++;    // Увеличиваем на 1
        }
        else
        {
            iRefCount = 1;  // Первое упоминание
            // Библиотека появилась ВПЕРВЫЕ (реально полезно!)
            OnFirstLibraryAdded(name);
        }
        g_hLibReferences.SetValue(name, iRefCount);
    }
    else
    {
        // Удаление: проверяем, что счетчик существует и больше нуля
        if (g_hLibReferences.GetValue(name, iRefCount) && iRefCount > 0)
        {
            iRefCount--;
            if (iRefCount == 0)
            {
                g_hLibReferences.Remove(name);
                // Библиотека исчезла ПОЛНОСТЬЮ
                OnLastLibraryRemoved(name);
            }
            else
            {
                g_hLibReferences.SetValue(name, iRefCount);
            }
        }
    }
}

public void OnLibraryAdded(const char[] name)
{
    OnLibraryChange(name, true);
}

public void OnLibraryRemoved(const char[] name)
{
    OnLibraryChange(name, false);
}

Управление:
Код
// Проверка, доступна ли библиотека прямо сейчас
bool IsLibraryAvailable(const char[] name)
{
    int iRefCount;
    return (g_hLibReferences.GetValue(name, iRefCount) && iRefCount > 0);
}

// Ваши кастомные обработчики (заглушки)
void OnFirstLibraryAdded(const char[] name)
{
    PrintToServer("[System] Library '%s' is now AVAILABLE (first registration)", name);
    // Здесь можно безопасно подключать хуки или создавать ресурсы
}

void OnLastLibraryRemoved(const char[] name)
{
    PrintToServer("[System] Library '%s' is now GONE (last unregistered)", name);
    // Здесь можно чистить ресурсы, только когда они точно никому не нужны
}
 
_wS_ Дата: Суббота, 09.05.2026, 06:18:02 | Сообщение # 3
Это избыточно.

Цитата TXCodding ()
Вместо глобальных переменных

Создаём другую и кэшируем каждую библиотеку, хотя нас интересует лишь одна конкретная.
Зачем?
Обычно создают одну bool переменную "существует ли библиотека", а int g_Library_L = 0; это её безопасная версия.

---
Плюс IsLibraryAvailable лезет в StringMap, что куда тяжелее, чем if (g_Library_L), особенно если это в OnGameFrame. Ну, как api, может кому и пригодится. Подсчёт ссылок это правильно, но почти всегда нужна лишь одна библиотека, а ради одной создавать StringMap и швырять туда все библиотеки, ну не знаю.
 
TXCodding Дата: Суббота, 09.05.2026, 13:03:19 | Сообщение # 4
Сообщений: 5
Репутация: 0 [ +/- ]
Ну да логика есть.
Код
static int g_iLibCounter_L;

public void OnLibraryAdded(const char[] name)
{
    if (StrEqual(name, "L") && ++g_iLibCounter_L == 1) {
        // Библиотека появилась впервые — делаем инициализацию
    }
}

public void OnLibraryRemoved(const char[] name)
{
    if (StrEqual(name, "L") && g_iLibCounter_L > 0 && --g_iLibCounter_L == 0) {
        // Библиотека исчезла полностью — делаем очистку
    }
}

// Проверка доступности — лёгкая и быстрая
bool IsLibraryAvailable()
{
    return g_iLibCounter_L > 0;
}

Так проще
 
  • Страница 1 из 1
  • 1
Поиск: