Что исправлено:
1. ИСПРАВЛЕНИЕ УТЕЧЕК ПАМЯТИ (MEMORY LEAKS)
sourcepawn
// БЫЛО (утечка памяти):
new Handle:hQuery = SQL_Query(g_hDatabase, query);
// ... работа с запросом ...
// НЕТ CloseHandle(hQuery) - ПАМЯТЬ НЕ ОСВОБОЖДАЛАСЬ!
// СТАЛО (память освобождается):
new Handle:hQuery = SQL_Query(g_hDatabase, query);
if (hQuery != INVALID_HANDLE)
{
// ... работа с запросом ...
CloseHandle(hQuery); // ВАЖНО! Всегда закрываем
}
Где исправлено: Во всех SQL запросах добавлен CloseHandle()
2. ЗАЩИТА ОТ SQL-ИНЪЕКЦИЙ
Проблема:
Злоумышленник мог ввести специальные символы в ник или причину бана и выполнить свой SQL код.
Что исправлено:
sourcepawn
// БЫЛО (опасно):
Format(query, sizeof(query), "SELECT * FROM specbans WHERE name = '%s'", name);
// СТАЛО (безопасно):
decl String:escapedName[SPECBAN_NAME_LENGTH * 2 + 1];
SQL_EscapeString(g_hDatabase, name, escapedName, sizeof(escapedName));
Format(query, sizeof(query), "SELECT * FROM specbans WHERE name = '%s'", escapedName);
Где исправлено: Во всех SQL запросах с пользовательским вводом
3. ИСПРАВЛЕНИЕ КРАШЕЙ ПРИ ДИСКОННЕКТЕ
Проблема:
Таймеры использовали прямой client индекс, который становился невалидным после выхода игрока.
Что исправлено:
sourcepawn
// БЫЛО (краш при дисконнекте):
CreateTimer(1.0, Timer_Unban, client);
// СТАЛО (безопасно):
CreateTimer(1.0, Timer_Unban, GetClientUserId(client));
// И в таймере:
public Action:Timer_Unban(Handle:timer, any:userid)
{
new client = GetClientOfUserId(userid); // Получаем клиента по userid
if (!client) return Plugin_Stop; // Если игрок ушел - ничего не делаем
// ... остальной код
}
Где исправлено: Во всех таймерах (Timer_Unban, Timer_ForceSpec, Timer_DelayedHint)
4. ИСПРАВЛЕНИЕ ОТРИЦАТЕЛЬНОГО ВРЕМЕНИ
Проблема:
Админ мог ввести отрицательное время бана, что ломало логику.
Что исправлено:
sourcepawn
// БЫЛО:
SpecBanPlayer(client, target, time, reason); // time мог быть -5
// СТАЛО:
if (time < 0)
{
LogError("Попытка бана с отрицательным временем: %d", time);
time = 0; // Превращаем в перманентный бан
}
5. ИСПРАВЛЕНИЕ ДУБЛИРОВАНИЯ КОДА
Проблема:
Один и тот же код для поиска SteamID в списке был в нескольких местах.
Что исправлено:
sourcepawn
// БЫЛО: код повторялся 3 раза
for (new i = 0; i < count; i++)
if (strcmp(list, steamid) == 0) return true;
// СТАЛО: вынесли в отдельную функцию
bool:IsSteamIDInList(String:list[][SPECBAN_STEAMID_LENGTH], count, const String:steamid[])
{
for (new i = 0; i < count; i++)
if (strcmp(list, steamid) == 0) return true;
return false;
}
6. ИСПРАВЛЕНИЕ ДЛЯ SM 1.1 СИНТАКСИСА
Проблема:
Новый синтаксис (char[], public void) не работает на старых версиях SourceMod.
Что исправлено:
sourcepawn
// БЫЛО (новый синтаксис):
public void OnPluginStart() { }
char name[64];
ArrayList list;
// СТАЛО (старый синтаксис SM 1.1):
public OnPluginStart() { }
new String:name[64];
new Handle:list;
Все изменения:
- char[] → String:[]
- public void → public
- delete → CloseHandle
- ArrayList → Handle
- Menu → Handle с CreateMenu/AddMenuItem
7. ОПТИМИЗАЦИЯ БАЗЫ ДАННЫХ
Добавлены индексы для ускорения:
sql
idx_steam_history_main - поиск связанных аккаунтов
idx_steam_history_linked - поиск по связанным SteamID
idx_name_history_steam - история ников по SteamID
idx_ban_history_steam - история банов
idx_ban_history_name - поиск по никам
idx_ban_history_endtime - автоочистка истекших банов
8. ИСПРАВЛЕНИЕ РУССКИХ СИМВОЛОВ
Проблема:
Русские символы в никах вызывали ошибки SQL.
Что исправлено:
sourcepawn
// БЫЛО (краш с русскими символами):
Format(query, sizeof(query), "INSERT INTO name_history (name) VALUES ('%s')", name);
// СТАЛО (работает с любыми символами):
SQL_EscapeString(g_hDatabase, name, escapedName, sizeof(escapedName));
Format(query, sizeof(query), "INSERT INTO name_history (name) VALUES ('%s')", escapedName);
9. ИСПРАВЛЕНИЕ СКЛОНЕНИЙ ВРЕМЕНИ
Проблема:
Неправильные окончания: "1 минут", "2 минут", "5 минута"
Что исправлено:
sourcepawn
// ТЕПЕРЬ ПРАВИЛЬНО:
1 минута
2 минуты
5 минут
11 минут (исключение)
21 минута
10. ОЧИСТКА ПРИ ПЕРЕЗАГРУЗКЕ
Добавлена функция ResetPlayerBanData:
sourcepawn
ResetPlayerBanData(client)
{
// Очищаем все данные игрока при выходе
if (g_hSpecBanTimer[client] != INVALID_HANDLE)
{
KillTimer(g_hSpecBanTimer[client]);
g_hSpecBanTimer[client] = INVALID_HANDLE;
}
g_bPermanentSpecBan[client] = false;
g_iBanEndTime[client] = 0;
g_sBanReason[client][0] = '\0';
// ... остальные данные
}
ИТОГ: ЧТО БЫЛО ИСПРАВЛЕНО
Проблема Было Стало Утечки памяти 12+ мест
Все CloseHandle()
SQL-инъекции Опасно
Экранирование
Краши при дисконнекте Да
userid защита
Отрицательное время Баг
Проверка
Дублирование кода 3 раза
1 функция
Русские символы Краш
Работает
Склонения времени Неправильно
Правильно
Индексы БД Нет
6 индексов
Очистка памяти Нет
ResetPlayerBanData
РЕЗУЛЬТАТ
Плагин теперь:
Версия 1.5 - стабильный релиз без утечек памяти и критических багов!
Не теряет память (все Handle закрыты)
Безопасен (нет SQL-инъекций)
Не крашится при дисконнекте
Работает на SM 1.1 (CSS V34)
Поддерживает русские символы
Правильно склоняет время
Быстро работает (индексы в БД)
Исправлены баги окончания срока бана:
Больше никаких -29522514 минут
Автовыход из спектаторов по таймеру
Что нового в версии 1.3
Общий чат – прозрачность для всех игроков
Теперь каждый бан отображается в общем чате в понятном двухстрочном формате:
[SpecBan] Администратор Petrov забанил Player123
[SpecBan] в спектаторы на 30 минут. Причина: Аимбот
Преимущества нового формата:
Особенность Описание Двухстрочный формат Даже самые длинные ники и причины никогда не обрезаются Цветовое выделение Ключевая информация (админ, игрок, срок, причина) выделена цветом и сразу бросается в глаза Понятно всем Обычные игроки видят, кто, кого, на сколько и за что наказал — прозрачность и справедливость Структурированность Информация разбита на логические блоки, легко читается даже в быстром чате Без обрезаний Никаких "...", никакой потери инф
Личное уведомление – забаненный игрок получает персональное сообщение
[SpecBan] Администратор Petrov забанил вас на 30 минут. Причина: Аимбот
Игрок точно знает, за что получил бан
Нет путаницы – сообщение приходит только ему
Детальная информация для админа – только администратор, выдавший бан, видит полные данные:
[SpecBan] === ИНФОРМАЦИЯ О БАНЕ ===
[SpecBan] Ник игрока: Player123
[SpecBan] SteamID: STEAM_0:0:143752713
[SpecBan] IP: 192.168.1.1
[SpecBan] Дата бана: 17.02.2026 15:30
[SpecBan] Срок окончания: 17.02.2026 16:00
[SpecBan] Причина: Аимбот
[SpecBan] Забанил: Petrov
Вся необходимая информация сразу после бана
Не нужно лезть в логи или базу данных
IP и SteamID сохраняются для истории
Умные склонения
Автоматически подбираются правильные окончания для срока бана:
Срок Отображается как 1 минута "1 минуту" 2-4 минуты "2 минуты", "3 минуты", "4 минуты" 5+ минут "5 минут", "30 минут" 0 минут "навсегда" Для администраторов
Преимущество Описание Мгновенная информация При бане сразу показываются все данные Без лишних действий Не нужно проверять через !checkplayer Чистота чата Обычные игроки не видят техническую информацию Удобное меню Все операции в пару кликов через !specban Проверка игрока
!checkplayer <SteamID или ник>
Команда показывает полную информацию об игроке:
Что отображается:
Раздел Детали Активный бан Есть ли бан сейчас, срок, причина, кто забанил История банов Все прошлые баны (до 10 последних) История ников Все ники, которые использовал игрок Связанные аккаунты Другие SteamID этого же человека Пример вывода:
[SpecBan] === ИНФОРМАЦИЯ ОБ ИГРОКЕ ===
[SpecBan] Активных банов нет.
[SpecBan] === ИСТОРИЯ БАНОВ ===
[SpecBan] 1. Бан от 15.02.2026 20:15
[SpecBan] Ник: Player123 | Срок: 15.02.2026 21:00 | Статус: Истёк
[SpecBan] Причина: Оскорбления | Забанил: Admin2
[SpecBan] === ИСТОРИЯ НИКОВ ===
[SpecBan] - Player123 | Период: 16.02.2026 - 16.02.2026
[SpecBan] - NoobKiller | Период: 17.02.2026 - 17.02.2026
Автоматическое обнаружение связанных SteamID по IP
Как это работает:
- Игрок заходит с нового аккаунта
- Плагин проверяет IP в истории
- Если IP совпадает со старым аккаунтом – создаётся связь
Предупреждение админов при обнаружении:
[SpecBan] [ВНИМАНИЕ] У игрока Player123 обнаружены связанные аккаунты:
[SpecBan] - SteamID: STEAM_0:0:111111 | Ник: OldPlayer1
[SpecBan] - SteamID: STEAM_0:0:222222 | Ник: OldPlayer2
[SpecBan] Всего найдено связанных аккаунтов: 2
Защита от обхода банов
Прозрачность – админ видит всю историю
Автоматически – не нужно ничего настраивать
Команды плагина
Команда Описание Доступ !specban Открыть меню бана/разбана Админ !checkplayer Проверить историю игрока Админ Меню !specban:
- Забанить игрока – выбор игрока, времени и причины
- Разбанить игрока – список забаненных с деталями
Итог:
Функция Описание Общий чат Двухстрочные уведомления, ничего не обрезается Личные уведомления Игрок знает причину бана Информация для админа Полные данные сразу после бана Умные склонения Правильные окончания для срока Проверка игрока Полная история в одной команде Защита от мультиаккаунтов Автоматическое обнаружение связей История банов Все баны хранятся навсегда
Что нового в меню разбана:
- SteamID игрока
- Дата и время бана
- Срок окончания (или "Навсегда")
- Причина бана
- Кто забанил
- Удобное управление– информация отображается прямо в меню, после чего можно:
- Подтвердить разбан нажатием одной кнопки
- Вернуться назад к списку забаненных
- Всё наглядно – больше не нужно вспоминать или искать в логах, за что и когда был забанен игрок. Вся информация под рукой!
- Чистота в чате – теперь при разбане показывается только одно сообщение:
Администратор "ник админа" разбанил из зрителей "ник игрока"- Убраны лишние уведомления – удалены дублирующиеся сообщения "Игрок разбанен" и прочие информационные спамы
- Умная подстановка ника – если данного игрока нет на сервере, его ник автоматически берётся из базы данных SQLite
Важно о безопасности:
Даже если администратор забанил другого администратора на этом же игровом сервере в спектра, узнав его настоящий SteamID в базе данных SQLite – это не даст ему несанкционированного доступа к чужим админским привилегиям. Ведь такой администратор не сможет авторизоваться под чужим SteamID, пока не узнает его секретный пароль для доступа к панели другого администратора.
Чем сложнее пароль – тем надёжнее защита ваших админских прав! Используйте уникальные комбинации, чтобы обезопасить свой доступ к админским полномочиям.