Руководство

Как настроить права на сервере Counter-Strike 2, управлять группами и игроками командами и проверять права из своего плагина.

В руководстве две части. Первая для владельцев серверов: хранилище, настройки и команды. Вторая для авторов плагинов: как проверять и менять права через API.

Строки прав

Право это строка из сегментов, разделённых точками. Плагины сами выбирают свои строки, обычно начиная их с имени плагина.

СтрокаЗначение
admin.kickОдно право
admin.*Всё внутри admin.
*Всё
-admin.banЗапрет: запрещает admin.ban
  • * может быть только последним сегментом. Пустые сегменты (a..b, a.) не допускаются.
  • admin.* покрывает admin.kick, а обычная строка admin не покрывает.
  • Запретом отнимают одно право у того, у кого есть wildcard: admin.* вместе с -admin.ban.

Как решается проверка

Когда право проверяется для игрока, побеждает первое место, которое знает ответ:

  1. временные права игрока;
  2. постоянные права игрока;
  3. группы игрока, от самого высокого приоритета к самому низкому. Сначала спрашивается сама группа, затем её родитель, затем родитель родителя.

Поэтому собственные права игрока перекрывают группы, а группа с более высоким приоритетом перекрывает группу с более низким.

Иммунитет

У каждого игрока есть уровень иммунитета. Администратор может действовать на игрока, только когда иммунитет администратора равен или выше. Иммунитет -1 означает «взять приоритет моей старшей группы».

Владельцам серверов

Установка

Все три плагина входят в билд Plugify Source 2 и сразу работают с базой SQLite. Как поставить их отдельно, описано на странице Установка.

Хранилище

Плагин хранилища держит настройки в permissions_storage.settings.yaml. Значения по умолчанию лежат рядом с плагином. Чтобы изменить их, создайте configs/permissions/permissions_storage.settings.yaml с теми ключами, которые меняете:

configs/permissions/permissions_storage.settings.yaml
storage_method: mysql
server_id: 1
data:
  host: "127.0.0.1"
  port: 3306
  username: "plugify"
  password: "secret"
  database: "permissions"
НастройкаЗначение
storage_methodsqlite3 (по умолчанию), mysql или postgres
dataПодключение к MySQL или PostgreSQL: host, port, username, password, database, schema (PostgreSQL), params и pool_settings
server_idId этого сервера. 0 означает все серверы: группы и права, выданные на сервере 0, действуют везде
global_cookieОбщие cookie для всех серверов вместо отдельных на каждый сервер
delete_expired_recordsУдалять из базы истёкшие группы и права
delete_removed_recordsУдалять из базы снятые группы и права, а не помечать их
  • SQLite не требует настройки. База лежит в data/permissions/permissions.db и создаётся при первом запуске с группой Default, которую получает каждый игрок. SQLite всегда работает как сервер 0.
  • Таблицы MySQL и PostgreSQL плагин не создаёт. Создайте их до первого запуска скриптом tables_mysql.sql или tables_postgres.sql из репозитория permissions-storage.

Настройки коннектора

Коннектор так же читает permissions_connector_s2.settings.yaml, правки кладутся в configs/permissions/:

НастройкаЗначение
notify_modeКуда приходят уведомления игрокам: console, chat, hint, каждое true или false
hint_durationСколько секунд подсказка остаётся на экране
time_modeЕдиница <duration> в командах: 0 секунды, 1 минуты, 2 часы, 3 дни
abbreviate_timeСокращённые единицы (5 мин.) вместо полных слов
format_timestampФормат даты в виде Go layout, например 2006-01-02 15:04:05
display_active_groupsПоказывать игрокам их активные группы при входе
hidden_groupsГруппы, которые игрокам не показываются, по умолчанию Default

Фразы лежат в permissions_connector_s2.translations.yaml. Чтобы изменить их, положите свою копию в data/permissions/. Применить изменения без перезапуска можно командами perms_reload_cfg и perms_reload_translations.

Команды

Команды работают в консоли сервера и в чате. Из консоли сервера разрешено всё. Игроку нужно право из таблицы, и он не может действовать на игроков с более высоким иммунитетом.

<player> это #userid, $steamid64, &account_id или имя. <duration> это число в единицах time_mode, а 0 означает навсегда. В perms_creategroup передайте "", если родителя нет, а несколько прав запишите в кавычках через пробел.

КомандаПравоЧто делает
permsнетСписок доступных вам команд
perms_reload_cfgpermissions.reload_configПеречитать настройки
perms_reload_translationspermissions.reload_translationsПеречитать фразы
perms_userspermissions.user.listСписок игроков на сервере
perms_user_info <player>permissions.user.infoВсе сведения об игроке
perms_user_permissions <player>permissions.user.permission.infoПрава и запреты игрока
perms_user_groups <player>permissions.user.group.infoГруппы игрока
perms_user_check_permission <player> <permission>permissions.user.permission.checkПроверить право
perms_user_check_group <player> <group>permissions.user.group.checkПроверить, состоит ли игрок в группе
perms_user_add_permission <player> <permission> <duration>permissions.user.permission.addДобавить право или запрет
perms_user_set_permission <player> <permission> <duration>permissions.user.permission.setУстановить право или запрет с заменой текущего
perms_user_remove_permission <player> <permission>permissions.user.permission.removeСнять право или запрет
perms_user_add_group <player> <group> <duration>permissions.user.group.addДобавить группу
perms_user_set_group <player> <group> <duration>permissions.user.group.setУстановить группу с заменой срока
perms_user_remove_group <player> <group>permissions.user.group.removeСнять группу
perms_groupspermissions.listgroupsСписок групп
perms_group_info <group>permissions.group.infoСведения о группе
perms_group_permissions <group>permissions.group.permissionsПрава группы
perms_group_check_permission <group> <permission>permissions.group.permission.checkПроверить право группы
perms_creategroup <group> <priority> <parent> <permissions>permissions.creategroupСоздать группу
perms_deletegroup <group>permissions.deletegroupУдалить группу
perms_group_parent_set <child> <parent>permissions.group.parent.setЗадать родительскую группу
perms_group_parent_info <group>permissions.group.parent.infoПоказать родительскую группу
perms_group_parent_check <child> <parent>permissions.group.parent.checkПроверить, является ли группа родителем другой
perms_group_set_option <group> <option> <value>permissions.group.option.setЗадать опцию группы
perms_group_option <group> <option>permissions.group.optionПоказать опцию группы
perms_group_add_permission <group> <permission>permissions.group.permission.addДобавить право
perms_group_set_permission <group> <permission>permissions.group.permission.setУстановить право с заменой текущего
perms_group_remove_permission <group> <permission>permissions.group.permission.removeСнять право

Первая настройка

Выполните в консоли сервера, чтобы создать группу администраторов и выдать её себе:

perms_creategroup Admin 100 "" "admin.* permissions.*"
perms_user_add_group $76561198000000000 Admin 0

Игрок должен быть на сервере: пользователи загружаются при входе и выгружаются при выходе.

Авторам плагинов

Добавьте зависимость

my_plugin.pplugin
{
  "$schema": "https://raw.githubusercontent.com/untrustedmodders/plugify/refs/heads/main/schemas/plugin.schema.json",
  "name": "my_plugin",
  "version": "1.0.0",
  "description": "An example plugin",
  "author": "Your Name",
  "website": "https://example.com",
  "license": "MIT",
  "language": "golang",
  "entry": "bin/my_plugin",
  "dependencies": [
    { "name": "permissions", "constraints": ">=1.3.0" }
  ]
}

Примеры ниже написаны на Go и используют готовые биндинги, go get github.com/fr0nch/go-plugify-permissions. В других языках те же функции импортируются из плагина permissions, см. страницу Import Functions вашего языка.

Проверка права

package main

import (
    permissions "github.com/fr0nch/go-plugify-permissions"
)

// May this player use the kick feature of my plugin?
func canKick(steamID64 uint64) bool {
    return permissions.HasPermission(steamID64, "my_plugin.kick") == permissions.Status_Allow
}

// May the admin act on the target at all?
func canTarget(adminID, targetID uint64) bool {
    return permissions.CanAffectUser(adminID, targetID) == permissions.Status_Allow
}

HasPermission возвращает Status: Allow, Disallow, PermNotFound или TargetUserNotFound, когда игрок не загружен. Сравнивайте с Allow, тогда отсутствующее право означает «нет».

Изменение прав и подписка на изменения

// Give the VIP group for 30 days. pluginID is the id of your plugin.
expires := time.Now().Add(30 * 24 * time.Hour).Unix()
status := permissions.AddGroup(pluginID, steamID64, "VIP", expires, false)
if status > permissions.Status_ErrorsStart {
    // GroupNotFound, TargetUserNotFound, DBNotReady and so on
}

// React to changes
permissions.OnUserGroupChange_Register(func(pluginID int64, action permissions.Action,
    targetID uint64, group string, oldTimestamp int64, newTimestamp int64) {
    // action is Action_Add, Action_Remove or Action_Replace
})
  • Время задаётся как Unix-время момента, когда право или группа истекает. 0 означает навсегда.
  • Функции, которые что-то меняют, принимают pluginID, он передаётся в колбэки, и dontBroadcast, с которым изменение применяется без уведомления подписчиков.
  • Любой статус больше ErrorsStart является ошибкой.
  • AddPermission отказывается менять право, которое уже есть с противоположным состоянием (PermConflict). SetPermission его заменяет.

Основные функции

ФункцияНазначение
HasPermission(targetID, perm)Проверить право пользователя
HasPermissionExtended(targetID, perm, exact, permSource, timestamp)То же, и сообщает, откуда пришло право и когда оно истекает
AddPermission, SetPermission, RemovePermissionИзменить права пользователя
HasGroup, AddGroup, RemoveGroup, GetUserGroupsГруппы пользователя
GetImmunity, SetImmunity, CanAffectUserИммунитет
GetCookie, SetCookie, GetAllCookiesИменованные значения для каждого пользователя
CreateGroup, DeleteGroup, GroupExists, GetAllGroupsГруппы
SetParent, GetParent, HasParentGroup, GetPriorityGroupИерархия групп
HasPermissionGroup, AddPermissionGroup, SetPermissionGroup, RemovePermissionGroupПрава группы
GetOptionGroup, SetOptionGroup, GetAllOptionsGroupОпции группы
UserExists, DumpUsersList, DumpPermissionsЧто загружено сейчас

События

У каждого события есть пара функций, On<Event>_Register и On<Event>_Unregister.

СобытиеКогда срабатывает
OnUserLoadedПользователь загружен со всеми группами и правами
OnUserCreate, OnUserDeleteПользователь появился в ядре или удалён
OnUserPermissionChange, OnUserGroupChangeПраво или группа пользователя добавлены, заменены или сняты
OnUserCookieChange, OnUserImmunityChangeИзменились cookie или иммунитет пользователя
OnPermissionExpiration, OnGroupExpirationИстекло временное право или группа
OnGroupCreate, OnGroupDelete, OnSetParentГруппы созданы, удалены или связаны
OnGroupPermissionChange, OnGroupOptionChangeИзменились право или опция группы
OnGroupsLoadedГруппы сервера загружены

Своё хранилище или коннектор

Ядро само ничего не загружает. LoadGroups и LoadUser вызывают колбэки OnGroupsLoad и OnUserRequest, а плагин, который их зарегистрировал, наполняет ядро через CreateGroup, CreateUser, AddGroup, AddPermission и SetCookie.

Чтобы сохранять изменения, зарегистрируйте колбэки хранилища: OnUserPermissionChangeStorage, OnUserGroupChangeStorage, OnUserCookieChangeStorage, OnUserImmunityChangeStorage, OnGroupCreateStorage, OnGroupDeleteStorage, OnGroupPermissionChangeStorage, OnGroupOptionChangeStorage и OnSetParentStorage. Они вызываются до применения изменения и возвращают bool. Если вернуть false, изменение отменяется, а вызвавший получает статус DBNotReady.

Полный список функций, колбэков и кодов статуса есть на API Hub.