AMX Mod X · Counter-Strike 1.6

Плагины для CS 1.6 на TypeScript.

Пишите плагин так же, как любой код на TypeScript: привычные типы, классы, Map, async/await, события. amxts компилирует его в WebAssembly, затем заранее в машинный код и запускает внутри модуля AMX Mod X — рядом с вашими Pawn-плагинами.

import { Player, 
plugin
,
print
,
server
} from "~/facade";
plugin
({
name
: "Say HP",
version
: "1.0.0",
author
: "Author",
description
: "An example",
});
server
.
addCommand
("/hp", sayHp);
server
.
addEventListener
("putinserver", (
event
) => {
print
(0, `${
event
.
player
.
name
} joined`);
}); function sayHp(
player
: Player) {
print
(
player
, `${
player
.
name
}, your HP: ${
player
.
health
}`);
if (
player
.
health
< 50)
player
.
health
= 100;
}

TypeScript, а не новый язык

Плагин — обычный TypeScript. Всё, что нужно AssemblyScript и Pawn — ячейки, битовые представления дробных, строковые буферы — спрятано под капот: в фасад и сгенерированные нативы.

    Привычные типы

    Классы, массивы, Map, шаблонные строки, number и string. Здоровье игрока задаётся как player.health = 100, без поиска нужного натива.

    Редактор знает игру

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

    async и await

    Настоящий Promise: await sleep(1000), await fetch(url), .then и .catch. Остаток функции выполняется в одном из следующих кадров, а сервер тем временем занят остальным.

    События как в DOM

    server.addEventListener("putinserver", ...) для событий AMX Mod X, game.addEventListener("takeDamage", ...) для хукчейнов reapi, event.preventDefault(), чтобы заблокировать.

    Сохранил и играешь

    Сохранил файл — работающий сервер пересобрал и перезагрузил плагин. Без amxxpc, без смены карты, никого не выкидывает.

    Тесты без сервера

    Тесты на Vitest или bun test: поддельный сервер запускает настоящий собранный плагин. Игроки заходят, пишут команды, а таймеры идут, когда это скажет тест.

Под капотом

Заранее скомпилирован, работает внутри AMX Mod X

amxts ничего не переводит в Pawn. Плагин компилируется в WebAssembly компилятором AssemblyScript, затем в машинный код i386 утилитой wamrc из WAMR, и модуль amxts_amxx загружает результат. Натив ищется по имени, поэтому доступен любой натив любого загруженного модуля — и любого другого плагина.

    Машинный код, а не интерпретатор

    Плагин компилируется в машинный код до того, как сервер его загрузит.

    Любой натив, с типами

    Генератор читает .inc-файлы и описывает каждый натив с его сигнатурой: reapi, hamsandwich и cstrike доступны, как только есть их инклуд.

Сборка say-hp.ts AssemblyScript .wasm wamrc .aot

Сервер CS 1.6

AMX Mod X

amxts_amxx

запускает ваши плагины .aot через WAMR

say-hp.aot загружен

amxts_host.amxx

сгенерирован, без логики

нативы по имени

Модули и Pawn-плагины

reapi, hamsandwich, cstrike, ваши .amxx

Pawn продолжает работать

Pawn-плагины вызывают TypeScript

Каждая export function плагина — это натив AMX Mod X с настоящими типами, а сборка пишет .inc, который подключает Pawn-плагин.

/** A value from a config file, or false when the key is not there. */
export function cfg_get_value(
file
: string,
section
: string,
key
: string) {
return lookup(
file
,
section
,
key
); // string | null
}

Меню, конфиги и HTTP — это модули

menu-core, config-core и http сделаны вместе с фреймворком, а любой модуль попадает в каталог через pull request в amxts/modules.