v1.3: разграничение прав, логирование, удалены blind/invertmouse
- Обычные админы (флаги abcdefghij без z) видят только меню Эффекты игрока - Группы DEIDARA/TESTER сохраняют полный доступ - Действия обычных админов логируются в addons/sourcemod/logs/super_admin_menu.log - Удалён эффект Ослепление на 2 сек - Удалён эффект Инверсия мыши
This commit is contained in:
@@ -1,13 +1,13 @@
|
||||
# Super Admin Menu
|
||||
|
||||
Расширенное меню администратора для CS:GO серверов на SourceMod. Открывается одной командой и предоставляет все нужные инструменты управления игроками.
|
||||
Расширенное меню администратора для CS:GO серверов на SourceMod. Открывается одной командой и предоставляет все нужные инструменты управления игроками с разграничением прав.
|
||||
|
||||
## Функции
|
||||
|
||||
- Выдача снаряжения (сет с оружием): AK-47, M4A4, M4A1-S, AWP, Deagle Only
|
||||
- Выдача денег: 3000 / 5000 / 10000 / 16000$
|
||||
- Респавн игроков (себе / всем / конкретному игроку)
|
||||
- Восстановление 100 HP + 100 Armor (только группы DEIDARA / TESTER)
|
||||
- Восстановление 100 HP + 100 Armor
|
||||
- Невидимость для администратора с сокрытием оружия
|
||||
- Телепорт к игроку / телепорт игрока к себе
|
||||
- Телепорт на плент A или B (автоопределение по карте)
|
||||
@@ -17,10 +17,9 @@
|
||||
- Drug-эффект (дёргание экрана + случайный FOV)
|
||||
- Случайный FOV
|
||||
- Инверсия движения
|
||||
- Инверсия мыши
|
||||
- Сильное сотрясение экрана
|
||||
- Ослепление на 2 секунды
|
||||
- Все действия логируются в чат онлайн-администраторам
|
||||
- Уведомления о действиях в чате членам групп DEIDARA / TESTER
|
||||
- Логирование действий обычных админов в файл
|
||||
|
||||
## Зависимости
|
||||
|
||||
@@ -38,18 +37,51 @@
|
||||
|
||||
| Команда | Доступ | Описание |
|
||||
|---|---|---|
|
||||
| `!sadmin` / `sm_sadmin` | Root или группа DEIDARA/TESTER | Открыть супер-админ меню |
|
||||
| `!sadmin` / `sm_sadmin` | Группа DEIDARA / TESTER или обычный админ (флаги `a`–`j`) | Открыть супер-админ меню |
|
||||
|
||||
## Уровни доступа
|
||||
|
||||
| Уровень | Возможности |
|
||||
|---|---|
|
||||
| Root (`ADMFLAG_ROOT`) | Все функции меню |
|
||||
| Группа **DEIDARA** | Все функции меню |
|
||||
| Группа **TESTER** | Все функции меню |
|
||||
| Группа **DEIDARA** | Все функции меню (полный доступ) |
|
||||
| Группа **TESTER** | Все функции меню (полный доступ) |
|
||||
| Обычный админ (любые флаги `abcdefghij`, без `z`) | Только меню «Эффекты игрока» |
|
||||
| Без админ-флагов | Доступ запрещён |
|
||||
|
||||
> Базовые функции (сет, деньги, респавн) доступны всем Root-админам. Расширенные функции (невидимость, телепорт, эффекты, восстановление HP) — только группам DEIDARA и TESTER.
|
||||
> Группы DEIDARA / TESTER определяются по имени группы в `admin_groups.cfg` (регистр не важен) — флаги роли не нужны.
|
||||
> Обычные админы — все, у кого есть любой флаг кроме `z` (Root) и кто не состоит в группах DEIDARA/TESTER. Им доступно только подменю «Эффекты игрока» с полным набором эффектов.
|
||||
|
||||
## Логирование
|
||||
|
||||
Все действия **обычных админов** в подменю «Эффекты игрока» автоматически пишутся в лог-файл:
|
||||
|
||||
```
|
||||
addons/sourcemod/logs/super_admin_menu.log
|
||||
```
|
||||
|
||||
Формат записи:
|
||||
```
|
||||
[YYYY-MM-DD HH:MM:SS] АдминИмя (STEAM_X:Y:Z) -> Действие -> ВКЛ/ВЫКЛ на игроке Имя (STEAM_X:Y:Z)
|
||||
```
|
||||
|
||||
Примеры:
|
||||
```
|
||||
[2026-05-01 18:42:11] AdminBob (STEAM_1:0:12345) -> 0 урона -> ВКЛ на игроке player1 (STEAM_1:1:67890)
|
||||
[2026-05-01 18:42:34] AdminBob (STEAM_1:0:12345) -> Тряска экрана на игроке player2 (STEAM_1:0:55555)
|
||||
```
|
||||
|
||||
Действия членов групп DEIDARA / TESTER в файл **не пишутся** (они отображаются только в чате другим членам этих групп через `PrintToRootAdmins`).
|
||||
|
||||
## Версия
|
||||
|
||||
`1.2` — Автор: OpenAI + deidara.dev
|
||||
`1.3` — Автор: OpenAI + deidara.dev
|
||||
|
||||
### Changelog
|
||||
|
||||
- **1.3**
|
||||
- Разграничение прав: обычные админы (флаги `a`–`j`, без `z`) теперь имеют доступ только к меню «Эффекты игрока»
|
||||
- Полный доступ — только у групп DEIDARA / TESTER
|
||||
- Добавлено логирование действий обычных админов в `addons/sourcemod/logs/super_admin_menu.log`
|
||||
- Удалён эффект «Ослепление на 2 секунды»
|
||||
- Удалён эффект «Инверсия мыши»
|
||||
- **1.2** — Базовая версия меню
|
||||
|
||||
+102
-53
@@ -15,7 +15,6 @@ bool g_bSuperRecoil[MAXPLAYERS + 1];
|
||||
bool g_bDrugEffect[MAXPLAYERS + 1];
|
||||
bool g_bRandomFov[MAXPLAYERS + 1];
|
||||
bool g_bInvertMovement[MAXPLAYERS + 1];
|
||||
bool g_bInvertMouse[MAXPLAYERS + 1];
|
||||
Handle g_hDrugTimer[MAXPLAYERS + 1];
|
||||
Handle g_hRandomFovTimer[MAXPLAYERS + 1];
|
||||
int g_iEffectTargetUserId[MAXPLAYERS + 1];
|
||||
@@ -25,7 +24,7 @@ public Plugin myinfo =
|
||||
name = "Super Admin Menu",
|
||||
author = "OpenAI + deidara.dev",
|
||||
description = "Единое супер-админ меню по команде sm_sadmin",
|
||||
version = "1.2"
|
||||
version = "1.3"
|
||||
};
|
||||
|
||||
public void OnPluginStart()
|
||||
@@ -62,7 +61,6 @@ public void OnClientDisconnect(int client)
|
||||
g_bDrugEffect[client] = false;
|
||||
g_bRandomFov[client] = false;
|
||||
g_bInvertMovement[client] = false;
|
||||
g_bInvertMouse[client] = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -107,8 +105,7 @@ public Action Command_SuperAdminMenu(int client, int args)
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
bool hasRootFlag = (GetUserFlagBits(client) & ADMFLAG_ROOT) != 0;
|
||||
if (!hasRootFlag && !IsClientInAllowedGroup(client))
|
||||
if (!IsClientInAllowedGroup(client) && !IsRegularAdmin(client))
|
||||
{
|
||||
PrintToChat(client, "[SM] У тебя нет доступа к этому меню.");
|
||||
return Plugin_Handled;
|
||||
@@ -126,12 +123,11 @@ void ShowMainMenu(int client)
|
||||
|
||||
bool isDeidara = IsClientInAllowedGroup(client);
|
||||
|
||||
if (isDeidara)
|
||||
{
|
||||
menu.AddItem("sets", "Выдать сет");
|
||||
menu.AddItem("money", "Выдать деньги");
|
||||
menu.AddItem("respawn", "Респавн");
|
||||
|
||||
if (isDeidara)
|
||||
{
|
||||
menu.AddItem("restore", "Восстановить 100 HP / 100 Armor");
|
||||
menu.AddItem("invis", g_bInvisible[client] ? "Выключить невидимость" : "Включить невидимость");
|
||||
menu.AddItem("tp_to", "Телепорт к игроку");
|
||||
@@ -139,6 +135,11 @@ void ShowMainMenu(int client)
|
||||
menu.AddItem("plant", "Телепорт на плент");
|
||||
menu.AddItem("effects", "Эффекты игрока");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Обычный админ: только Эффекты игрока
|
||||
menu.AddItem("effects", "Эффекты игрока");
|
||||
}
|
||||
|
||||
menu.Display(client, MENU_TIME);
|
||||
}
|
||||
@@ -159,6 +160,20 @@ public int MenuHandler_Main(Menu menu, MenuAction action, int client, int item)
|
||||
|
||||
bool isDeidara = IsClientInAllowedGroup(client);
|
||||
|
||||
// Обычные админы могут открыть только меню эффектов
|
||||
if (!isDeidara && !StrEqual(info, "effects"))
|
||||
{
|
||||
PrintToChat(client, "[SM] У тебя нет доступа к этому пункту.");
|
||||
ShowMainMenu(client);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (StrEqual(info, "effects"))
|
||||
{
|
||||
ShowEffectTargetMenu(client);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (StrEqual(info, "sets"))
|
||||
{
|
||||
ShowTargetMenu(client, "set");
|
||||
@@ -171,11 +186,6 @@ public int MenuHandler_Main(Menu menu, MenuAction action, int client, int item)
|
||||
{
|
||||
ShowTargetMenu(client, "respawn");
|
||||
}
|
||||
else if (!isDeidara)
|
||||
{
|
||||
PrintToChat(client, "[SM] Этот пункт доступен только группам DEIDARA и TESTER.");
|
||||
ShowMainMenu(client);
|
||||
}
|
||||
else if (StrEqual(info, "restore"))
|
||||
{
|
||||
ShowTargetMenu(client, "restore");
|
||||
@@ -197,10 +207,6 @@ public int MenuHandler_Main(Menu menu, MenuAction action, int client, int item)
|
||||
{
|
||||
ShowPlantMenu(client);
|
||||
}
|
||||
else if (StrEqual(info, "effects"))
|
||||
{
|
||||
ShowEffectTargetMenu(client);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -875,9 +881,9 @@ void StripWeapons(int client)
|
||||
|
||||
void ShowEffectTargetMenu(int client)
|
||||
{
|
||||
if (!IsClientInAllowedGroup(client))
|
||||
if (!IsClientInAllowedGroup(client) && !IsRegularAdmin(client))
|
||||
{
|
||||
PrintToChat(client, "[SM] Этот пункт доступен только группам DEIDARA и TESTER.");
|
||||
PrintToChat(client, "[SM] У тебя нет доступа к этому меню.");
|
||||
ShowMainMenu(client);
|
||||
return;
|
||||
}
|
||||
@@ -915,12 +921,12 @@ void ShowEffectTargetMenu(int client)
|
||||
|
||||
public int MenuHandler_EffectTarget(Menu menu, MenuAction action, int client, int item)
|
||||
{
|
||||
if (!IsClientInAllowedGroup(client))
|
||||
if (!IsClientInAllowedGroup(client) && !IsRegularAdmin(client))
|
||||
{
|
||||
if (action == MenuAction_End)
|
||||
delete menu;
|
||||
else if (action == MenuAction_Select)
|
||||
PrintToChat(client, "[SM] Этот пункт доступен только группам DEIDARA и TESTER.");
|
||||
PrintToChat(client, "[SM] У тебя нет доступа к этому меню.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -949,9 +955,9 @@ public int MenuHandler_EffectTarget(Menu menu, MenuAction action, int client, in
|
||||
|
||||
void ShowEffectMenu(int client)
|
||||
{
|
||||
if (!IsClientInAllowedGroup(client))
|
||||
if (!IsClientInAllowedGroup(client) && !IsRegularAdmin(client))
|
||||
{
|
||||
PrintToChat(client, "[SM] Этот пункт доступен только группам DEIDARA и TESTER.");
|
||||
PrintToChat(client, "[SM] У тебя нет доступа к этому меню.");
|
||||
ShowMainMenu(client);
|
||||
return;
|
||||
}
|
||||
@@ -977,20 +983,18 @@ void ShowEffectMenu(int client)
|
||||
menu.AddItem("drug", g_bDrugEffect[target] ? "Выключить drug-эффект" : "Включить drug-эффект");
|
||||
menu.AddItem("randomfov", g_bRandomFov[target] ? "Выключить случайный FOV" : "Включить случайный FOV");
|
||||
menu.AddItem("invertmove", g_bInvertMovement[target] ? "Выключить инверсию движения" : "Включить инверсию движения");
|
||||
menu.AddItem("invertmouse", g_bInvertMouse[target] ? "Выключить инверсию мыши" : "Включить инверсию мыши");
|
||||
menu.AddItem("shake", "Сильно тряхнуть экран");
|
||||
menu.AddItem("blind", "Ослепить на 2 сек");
|
||||
menu.Display(client, MENU_TIME);
|
||||
}
|
||||
|
||||
public int MenuHandler_EffectMenu(Menu menu, MenuAction action, int client, int item)
|
||||
{
|
||||
if (!IsClientInAllowedGroup(client))
|
||||
if (!IsClientInAllowedGroup(client) && !IsRegularAdmin(client))
|
||||
{
|
||||
if (action == MenuAction_End)
|
||||
delete menu;
|
||||
else if (action == MenuAction_Select)
|
||||
PrintToChat(client, "[SM] Этот пункт доступен только группам DEIDARA и TESTER.");
|
||||
PrintToChat(client, "[SM] У тебя нет доступа к этому меню.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1025,41 +1029,37 @@ public int MenuHandler_EffectMenu(Menu menu, MenuAction action, int client, int
|
||||
{
|
||||
g_bZeroDamageAttack[target] = !g_bZeroDamageAttack[target];
|
||||
PrintToRootAdmins("[SM] %N: 0 урона для %N -> %s", client, target, g_bZeroDamageAttack[target] ? "ВКЛ" : "ВЫКЛ");
|
||||
LogAdminAction(client, target, "0 урона -> %s", g_bZeroDamageAttack[target] ? "ВКЛ" : "ВЫКЛ");
|
||||
}
|
||||
else if (StrEqual(info, "recoil"))
|
||||
{
|
||||
g_bSuperRecoil[target] = !g_bSuperRecoil[target];
|
||||
PrintToRootAdmins("[SM] %N: супер-отдача для %N -> %s", client, target, g_bSuperRecoil[target] ? "ВКЛ" : "ВЫКЛ");
|
||||
LogAdminAction(client, target, "Супер-отдача -> %s", g_bSuperRecoil[target] ? "ВКЛ" : "ВЫКЛ");
|
||||
}
|
||||
else if (StrEqual(info, "drug"))
|
||||
{
|
||||
ToggleDrugEffect(target);
|
||||
PrintToRootAdmins("[SM] %N: drug-эффект для %N -> %s", client, target, g_bDrugEffect[target] ? "ВКЛ" : "ВЫКЛ");
|
||||
LogAdminAction(client, target, "Drug-эффект -> %s", g_bDrugEffect[target] ? "ВКЛ" : "ВЫКЛ");
|
||||
}
|
||||
else if (StrEqual(info, "randomfov"))
|
||||
{
|
||||
ToggleRandomFov(target);
|
||||
PrintToRootAdmins("[SM] %N: случайный FOV для %N -> %s", client, target, g_bRandomFov[target] ? "ВКЛ" : "ВЫКЛ");
|
||||
LogAdminAction(client, target, "Случайный FOV -> %s", g_bRandomFov[target] ? "ВКЛ" : "ВЫКЛ");
|
||||
}
|
||||
else if (StrEqual(info, "invertmove"))
|
||||
{
|
||||
g_bInvertMovement[target] = !g_bInvertMovement[target];
|
||||
PrintToRootAdmins("[SM] %N: инверсия движения для %N -> %s", client, target, g_bInvertMovement[target] ? "ВКЛ" : "ВЫКЛ");
|
||||
}
|
||||
else if (StrEqual(info, "invertmouse"))
|
||||
{
|
||||
g_bInvertMouse[target] = !g_bInvertMouse[target];
|
||||
PrintToRootAdmins("[SM] %N: инверсия мыши для %N -> %s", client, target, g_bInvertMouse[target] ? "ВКЛ" : "ВЫКЛ");
|
||||
LogAdminAction(client, target, "Инверсия движения -> %s", g_bInvertMovement[target] ? "ВКЛ" : "ВЫКЛ");
|
||||
}
|
||||
else if (StrEqual(info, "shake"))
|
||||
{
|
||||
ApplyStrongShake(target);
|
||||
PrintToRootAdmins("[SM] %N сильно тряхнул экран игрока %N.", client, target);
|
||||
}
|
||||
else if (StrEqual(info, "blind"))
|
||||
{
|
||||
BlindPlayer(target, 2.0);
|
||||
PrintToRootAdmins("[SM] %N ослепил игрока %N на 2 сек.", client, target);
|
||||
LogAdminAction(client, target, "Тряска экрана");
|
||||
}
|
||||
|
||||
ShowEffectMenu(client);
|
||||
@@ -1106,12 +1106,6 @@ public Action OnPlayerRunCmd(int client, int &buttons, int &impulse, float vel[3
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (g_bInvertMouse[client])
|
||||
{
|
||||
mouse[1] = -mouse[1];
|
||||
changed = true;
|
||||
}
|
||||
|
||||
return changed ? Plugin_Changed : Plugin_Continue;
|
||||
}
|
||||
|
||||
@@ -1268,16 +1262,6 @@ void ApplyStrongShake(int client)
|
||||
CreateTimer(1.5, Timer_KillEntity, EntIndexToEntRef(shake), TIMER_FLAG_NO_MAPCHANGE);
|
||||
}
|
||||
|
||||
void BlindPlayer(int client, float duration)
|
||||
{
|
||||
if (!IsValidClient(client) || !IsPlayerAlive(client))
|
||||
return;
|
||||
|
||||
// Используем встроенные пропы флэшбанга CS:GO — никакого usermsgs, безопасно
|
||||
SetEntPropFloat(client, Prop_Send, "m_flFlashDuration", duration);
|
||||
SetEntPropFloat(client, Prop_Send, "m_flFlashMaxAlpha", 255.0);
|
||||
}
|
||||
|
||||
public Action Timer_KillEntity(Handle timer, any entRef)
|
||||
{
|
||||
int ent = EntRefToEntIndex(entRef);
|
||||
@@ -1317,6 +1301,25 @@ bool IsClientInAllowedGroup(int client)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Обычный админ: имеет любой админ-флаг, но НЕ имеет ROOT и НЕ в группах DEIDARA/TESTER
|
||||
bool IsRegularAdmin(int client)
|
||||
{
|
||||
if (!IsValidClient(client))
|
||||
return false;
|
||||
|
||||
if (IsClientInAllowedGroup(client))
|
||||
return false;
|
||||
|
||||
int flags = GetUserFlagBits(client);
|
||||
if (flags == 0)
|
||||
return false;
|
||||
|
||||
if ((flags & ADMFLAG_ROOT) != 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void PrintToRootAdmins(const char[] format, any ...)
|
||||
{
|
||||
char buffer[256];
|
||||
@@ -1335,3 +1338,49 @@ bool IsValidClient(int client)
|
||||
{
|
||||
return (client > 0 && client <= MaxClients && IsClientInGame(client));
|
||||
}
|
||||
|
||||
// Логируем действие обычного админа в файл addons/sourcemod/logs/super_admin_menu.log.
|
||||
// Действия DEIDARA/TESTER не логируются.
|
||||
void LogAdminAction(int client, int target, const char[] format, any ...)
|
||||
{
|
||||
if (!IsRegularAdmin(client))
|
||||
return;
|
||||
|
||||
char message[256];
|
||||
VFormat(message, sizeof(message), format, 4);
|
||||
|
||||
char path[PLATFORM_MAX_PATH];
|
||||
BuildPath(Path_SM, path, sizeof(path), "logs/super_admin_menu.log");
|
||||
|
||||
char timestamp[32];
|
||||
FormatTime(timestamp, sizeof(timestamp), "%Y-%m-%d %H:%M:%S");
|
||||
|
||||
char adminName[MAX_NAME_LENGTH], adminSteam[32];
|
||||
GetClientName(client, adminName, sizeof(adminName));
|
||||
if (!GetClientAuthId(client, AuthId_Steam2, adminSteam, sizeof(adminSteam)))
|
||||
strcopy(adminSteam, sizeof(adminSteam), "UNKNOWN");
|
||||
|
||||
char targetInfo[128];
|
||||
if (IsValidClient(target))
|
||||
{
|
||||
char targetName[MAX_NAME_LENGTH], targetSteam[32];
|
||||
GetClientName(target, targetName, sizeof(targetName));
|
||||
if (!GetClientAuthId(target, AuthId_Steam2, targetSteam, sizeof(targetSteam)))
|
||||
strcopy(targetSteam, sizeof(targetSteam), "UNKNOWN");
|
||||
Format(targetInfo, sizeof(targetInfo), "%s (%s)", targetName, targetSteam);
|
||||
}
|
||||
else
|
||||
{
|
||||
strcopy(targetInfo, sizeof(targetInfo), "UNKNOWN");
|
||||
}
|
||||
|
||||
File logFile = OpenFile(path, "a");
|
||||
if (logFile == null)
|
||||
{
|
||||
LogError("[super_admin_menu] Не удалось открыть %s для записи.", path);
|
||||
return;
|
||||
}
|
||||
|
||||
logFile.WriteLine("[%s] %s (%s) -> %s на игроке %s", timestamp, adminName, adminSteam, message, targetInfo);
|
||||
delete logFile;
|
||||
}
|
||||
Reference in New Issue
Block a user