Python 3.11+ API • SADEMP v0.2

Скриптинг серверов SADEMP

Руководство разработчика по написанию игровых режимов (RP, Дрифт, DM, Freeroam) и фильтрскриптов для сервера SADEMP на Python. Серверу нужен только Python 3.11+ — дополнительные библиотеки не требуются.

1. Быстрый старт

Скрипт в SADEMP — это обычный файл .py. Гейммод лежит в server/gamemodes/, фильтрскрипты — в server/filterscripts/. Какие из них загружать, указывается в server.toml. Фильтрскрипты получают события раньше гейммода (как в SA-MP).

from sademp import *             # всё API SADEMP
from sademp.compat import *      # + функции в стиле SA-MP (по желанию)

@on("game_mode_init")
def init():
    print("Сервер SADEMP успешно запущен!")
    set_world_time(12, 0)
    set_weather(1)

Скрипты можно раскладывать по подпапкам: файл filterscripts/mymod/x.py указывается в server.toml как "mymod/x". Запуск сервера: start_server.bat на Windows или sh start_server.sh на Linux.

2. Структура каталогов

Путь Назначение
server/server.tomlНастройки сервера: название, порт, пароли, список скриптов.
server/gamemodes/Игровой режим (пример — freeroam.py).
server/filterscripts/Фильтрскрипты (примеры — admin.py, accounts.py), можно в подпапках.
server/data/Базы и файлы данных скриптов: sqlite3.connect(data_path("my.db")).
server/logs/Журнал сервера server_log.txt.
server/sademp/Движок сервера. Не изменяйте — он обновляется вместе с SADEMP.
docs/SCRIPTING.mdКраткий справочник по API.
tools/bot.pyБоты для проверки сервера без запуска игры.
start_server.bat / start_server.shЗапуск сервера на Windows / Linux.

3. Конфигурация server.toml

[server]
name = "My SADEMP Server"
host = "0.0.0.0"
port = 7777                # UDP-порт; на хостинге его нужно открыть
max_players = 50
password = ""              # пусто = вход без пароля
rcon_password = "changeme" # ОБЯЗАТЕЛЬНО поменяйте
tick_rate = 30             # тиков сервера в секунду
stream_distance = 300.0    # дальность видимости игроков
debug = false

[master]
host = "127.0.0.1:7780"   # мастер-сервер SADEMP; пусто = не показывать во вкладке «Интернет»

[scripts]
gamemode = "freeroam"                   # файл gamemodes/freeroam.py
filterscripts = ["admin", "accounts"]   # файлы filterscripts/*.py (подпапки: "mymod/script")

Пока rcon_password равен "changeme", вход администратора через /rcon login не сработает — пароль нужно сменить.

4. Консоль и горячая перезагрузка

Перезапускать сервер после правок в скриптах не нужно. В консоли сервера доступны команды:

КомандаЧто делает
reload <имя>Перезагрузить загруженный скрипт (гейммод или фильтрскрипт).
load <имя>Загрузить фильтрскрипт из filterscripts/ (можно mymod/x).
unload <имя>Выгрузить скрипт.
scriptsСписок загруженных скриптов (GM — гейммод, FS — фильтрскрипт).
playersСписок игроков онлайн: id, ник, IP, пинг.
kick <id или ник>Кикнуть игрока.
say <текст>Сообщение всем игрокам от имени администратора.
exit / quit / stopОстановить сервер.

Свои команды консоли добавляются через событие rcon_command. При выгрузке скрипта автоматически удаляются его события, команды, таймеры, а также созданные им пикапы, 3D-тексты и текстдравы. Машины и объекты не удаляются — уничтожайте их сами в script_exit / game_mode_exit.

5. События — @on("имя")

Если обработчик вернул False, цепочка останавливается и событие считается отменённым (например, сообщение не уйдёт в общий чат, спавн будет запрещён).

Событие Аргументы Значение False
game_mode_init / game_mode_exit——
script_init / script_exit— (для фильтрскриптов)—
player_connectplayerКикнуть игрока при входе
player_disconnectplayer, reason (0 вылет, 1 выход, 2 кик)—
player_request_spawnplayerЗапретить спавн
player_spawnplayer—
player_deathplayer, killer, reason (killer — Player или None, reason — id оружия)—
player_textplayer, textНе рассылать сообщение в чат
player_commandplayer, "/cmd args" — только для команд без @commandКоманда обработана
player_updateplayer — каждый пакет синхронизацииНе пересылать другим игрокам
player_state_changeplayer, new_state, old_state—
player_enter_vehicleplayer, vehicle, is_passengerВыкинуть из транспорта
player_exit_vehicleplayer, vehicle—
player_take_damageplayer, issuer, amount, weapon, body_part—
player_enter_checkpoint / player_leave_checkpointplayer—
player_pickupplayer, pickup—
dialog_responseplayer, dialog_id, response, list_item, input_textОтвет обработан
rcon_commandcmd, args — неизвестная команда консолиКоманда обработана

6. Команды — @command

Сигнатура: @command("имя", "алиас", ..., help="", admin=False). Аргументы команды разбираются автоматически по аннотациям типов.

@command("pm", help="Отправить личное сообщение")
def pm(player: Player, target: Player, text: str):
    target.send_message(COLOR_YELLOW, f"ЛС от {player.name}: {text}")

@command("veh", "car", help="Создать машину")
def veh(player: Player, model: int, color1: int = -1, color2: int = -1):
    x, y, z = player.pos
    car = create_vehicle(model, x + 2.0, y, z, player.heading, color1, color2)
    player.put_in_vehicle(car)

7. Класс Player

Поля: id, name, ip, state, pos, heading, health, armor, weapon, skin, money, score, interior, virtual_world, vehicle, seat, color, team, is_admin, ping_ms, is_spawned и data — словарь для ваших данных.

player.pos — это вектор с полями .x, .y, .z. Его можно распаковать (x, y, z = player.pos), но нельзя индексировать: player.pos[0] вызовет ошибку.

МетодОписание
send_message(color, text)Сообщение в чат игрока
game_text(text, time_ms=3000, style=3)Крупный текст на экране
show_dialog(id, style, caption, info, button1="OK", button2="")Диалог; style — DialogStyle.MSGBOX / INPUT / LIST / PASSWORD / TABLIST
set_pos(x, y, z), set_heading(a), set_interior(i)Позиция, поворот, интерьер
set_virtual_world(w)Виртуальный мир: игроки в разных мирах не видят друг друга
set_health(hp), set_armor(arm)Здоровье / броня
give_weapon(id, ammo), reset_weapons()Оружие
set_money(v), give_money(v)Деньги
set_skin(id), set_color(rgba), set_wanted_level(n)Внешний вид и розыск
set_spawn_info(skin, x, y, z, heading=0, team=255), spawn()Точка спавна / заспавнить
put_in_vehicle(vehicle, seat=0), remove_from_vehicle()Посадить в транспорт / высадить
set_checkpoint(x, y, z, size=3.0), disable_checkpoint()Чекпоинт
set_map_icon(id, x, y, z, marker, color=0), remove_map_icon(id)Иконки на карте
set_camera(pos, look_at), camera_behind()Камера
set_time(h, m), set_weather(w)Время и погода только для этого игрока
toggle_controllable(bool)Заморозить / разморозить
distance_to(x, y, z)Расстояние до точки
kick(reason)Кикнуть игрока

8. Транспорт и объекты

car = create_vehicle(model, x, y, z, heading=0, color1=-1, color2=-1, respawn_delay=300)
car.set_pos(x, y, z); car.set_health(1000); car.repair(); car.set_color(1, 1)
car.respawn(); car.destroy()
car.driver        # Player или None
car.occupants     # список: водитель и пассажиры
car.data["owner"] = player.name   # ваши данные

obj = create_object(model, x, y, z, rx=0, ry=0, rz=0, draw_distance=300)
obj.move(x, y, z, speed)
obj.destroy()

Найти транспорт: get_vehicle(id), get_vehicles(). Машины и объекты не удаляются при выгрузке скрипта автоматически.

9. Пикапы, 3D-текст и текстдравы

# Пикап (аналог CreatePickup); подбор — событие player_pickup
pk = create_pickup(1240, 2, x, y, z, world=-1)   # world=-1 — во всех мирах

@on("player_pickup")
def on_pickup(player, pickup):
    if pickup is pk:
        player.set_health(100)

# 3D-текст в мире; "\n" — новая строка, {RRGGBB} — цвет
label = create_3d_text_label("Автосалон\n{33CCFF}/buycar", COLOR_WHITE, x, y, z, draw_distance=20)
label.update(text="Закрыто")

# Текстдрав (координаты экрана 640x448)
td = create_textdraw(320.0, 420.0, "SADEMP")
td.alignment = 2              # 1 влево, 2 по центру, 3 вправо
td.show_for(player); td.show_for_all()
td.set_text("Новый текст"); td.hide_for(player); td.destroy()

Свойства текстдрава (letter_size, color, font, alignment, box, box_color и др.) задаются атрибутами до показа; для уже показанного вызовите show_for() повторно. Эти три вида объектов удаляются автоматически при выгрузке скрипта.

10. Таймеры и утилиты

t = set_timer(func, 1000, repeat=True, *args)   # вызвать func через 1000 мс (повторять)
t.kill()                                         # или kill_timer(t)

get_players(); get_player(id); find_player("Ник или id")
send_message_to_all(color, text); game_text_for_all(text, time_ms, style)
set_world_time(hour, minute=0); set_weather(id)
server_name(); max_players(); rcon_password()
data_path("my.db")   # путь к файлу в server/data

Константы: COLOR_* (формат RGBA), WEAPON_*, DEATH_REASON_*, PlayerState, DialogStyle. В тексте сообщений цвет меняется вставками {RRGGBB}, как в SA-MP.

11. Перенос логики с Pawn (SA-MP)

Классический Pawn (SA-MP) Python (SADEMP)
public OnPlayerConnect(playerid)@on("player_connect") def f(player):
SendClientMessage(playerid, -1, "...")player.send_message(COLOR_WHITE, "...") или SendClientMessage(player.id, -1, "...") из compat
CMD:veh(playerid, params[]) + sscanf@command("veh") def veh(player, model: int):
SetTimerEx("F", 1000, true, "i", id)set_timer(f, 1000, True, player)
PlayerData[playerid][pCash]player.data["cash"]
mysql_query(...) (плагин)sqlite3 или любая библиотека из PyPI

Модуль sademp.compat содержит привычные функции с playerid: GetPlayerName, SetPlayerPos, GivePlayerWeapon, CreateVehicle, PutPlayerInVehicle, ShowPlayerDialog, SetTimer и другие. Коды цвета Pawn (-1 = белый) поддерживаются.

Серверная часть находится в разработке