Плагин и модули#
Каждый плагин начинается с одного объекта Plugin. Декораторы @plugin.on, @plugin.command
и остальные только записывают объявления, а регистрирует их рантайм при загрузке. Поэтому
модуль плагина можно импортировать без сервера — так его читает компилятор и тесты.
from amxpy import Plugin
plugin = Plugin(
"VIP", # название в amxpy list и логах
version="1.2.0",
author="you",
description="VIP-бонусы и API для Pawn",
url="https://example.com",
)
Название, версия и остальные метаданные должны быть строками-литералами: компилятор берёт их
из исходника, не запуская код (иначе — AMX003).
Что можно объявить#
| Декоратор или метод | Что это | Подробнее |
|---|---|---|
@plugin.on(events.X) |
обработчик события | События |
@plugin.command("/hp") |
команда игрока в чате или консоли | Команды |
@plugin.server_command("amx_x") |
команда консоли сервера и rcon | Команды |
@plugin.every(60) |
периодическая задача | Async и задачи |
@plugin.native |
натив для Pawn-плагинов | API для Pawn |
plugin.forward("x", ...) |
свой форвард | API для Pawn |
@plugin.on_forward("x") |
подписка на форвард Pawn, AMXX или Python | Форварды в Python |
@plugin.on_unload |
код при выгрузке и перезагрузке | Горячая перезагрузка |
Большой плагин — пакет из модулей#
Когда плагин растёт, он становится папкой. В каждом модуле — свой Router() с теми же
декораторами, а корневой __init__.py подключает их через plugin.include(...):
include принимает роутеры и конфиги и возвращает первый аргумент — поэтому
cfg = plugin.include(Settings()) сохраняет тип конфига для редактора.
Модули пакета импортируются как amxpy.plugins.<плагин>.<модуль>; используйте относительный
импорт (from . import perks). Остальные файлы пакета — переводы lang/*.toml и данные —
попадают в .amxpy вместе с кодом. Полный пример — VIP-система.
Подготовка — в Init, а не при импорте#
Код на верхнем уровне модуля выполняется при импорте — и компилятором тоже. Открывать файлы,
соединения и базы там нельзя (компилятор предупредит:
AMX301). Для этого есть событие Init:
@plugin.on(events.Init)
async def setup(e: events.Init) -> None:
await table.create()
if e.hot_reload:
plugin.log.info("перезагружен на лету")
Лог#
plugin.log — обычный logging.Logger, который пишет в лог сервера с именем плагина:
plugin.log.info("VIP загружено: %d", len(vips.values()))
plugin.log.warning("база недоступна, пробую ещё раз")
Исключение в обработчике не роняет сервер: оно попадает в лог с трассировкой, а счётчик
ошибок плагина виден в amxpy list.