Getting started

Installing on a server

A game server runs amxts plugins with two things: the amxts_amxx module and the addons/amxts folder with the plugins. This page puts them on a server of your own. The other way is the server in Docker, which has all of it inside.

What the server needs

  • Counter-Strike 1.6 on HLDS, Windows or Linux. ReHLDS is recommended.
  • Metamod and AMX Mod X 1.9 or later, with AMX Mod X's own modules engine, fakemeta, hamsandwich, cstrike and fun. amxts is tested on AMX Mod X 1.10 with Metamod-R.
  • ReGameDLL and ReAPI for every game event of ReGameDLL's and ReHLDS's own as the game raises it, and the game rules' fields ReGameDLL adds. Without them the plugin is written the same: the entity properties (players and entities) and the player actions (give, respawn, …) work through AMX Mod X's fun, cstrike, hamsandwich and fakemeta, and most game events are heard through them too, some with less (a server without ReAPI). A plugin asks with hasModule("reapi"). A project for such a server says target: "hlds" in amxts.config.ts (the server's includes), and a listener for an event nothing there hears does not build.
  • For .ts plugins compiled on the server: a 64-bit system - Windows x64, or Linux x86-64 with glibc 2.27 or newer. A 32-bit hlds_linux runs on it as it is. A server that only runs plugins built elsewhere does not need this.
Plain HLDS
On Valve's own HLDS - Metamod and AMX Mod X, no ReHLDS, ReGameDLL or ReAPI; checked on Linux with metamod-p - the events of ReGameDLL's and ReHLDS's own are heard through AMX Mod X's own modules, as a Pawn plugin hears them there. What is not there:
  • the events nothing there hears - the game rules' questions (fallDamage, canHaveItem, …), the player's movement (jumpMovement, move, …), the engine's own (printf, addResource, …), giveDefaultItems and the grenades' explosions: a listener for one is never called, and the server console says so once, when it is added;
  • what some of the heard ones cannot give - most come after the game has acted, so preventDefault() and a changed field do nothing there, and a few lack a field: the game events page lists them, and asking for it is one line in the console;
  • the game rules' fields teamBalanced, neededPlayers, skipShowMenu, escapeRatio and updateInterval: they read 0 and write nothing, said once; timeLimit and gameStartTime are counted from mp_timelimit;
  • ReAPI's own natives (get_entvar, get_member, rg_*): a call does nothing and answers 0, said once for each native.

The server kit

The kit is one archive per system, with everything that goes on the server:

systemarchivethe module
Windowsamxts-server-windows-x64.zipamxts_amxx.dll
Linuxamxts-server-linux-x64.tar.gzamxts_amxx_i386.so

Download it from the releases: the one of the same version as @amxts/core in your projects.

What is inside, laid out as it goes into the game folder (cstrike/):

addons/
├── amxmodx/
│   ├── modules/amxts_amxx.dll          amxts_amxx_i386.so on Linux
│   └── scripting/include/amxts.inc     for Pawn plugins: the fields plugins add to Player
└── amxts/
    ├── plugins.ini                     the amxts plugin list: hello.ts
    ├── plugins/                        your plugins, and beside them:
    │   ├── hello.ts                    an example plugin
    │   ├── facade.ts, natives.ts, …    the API a plugin uses
    │   ├── imports.d.ts                what a plugin uses without an import, for the editor
    │   ├── tsconfig.json               for an editor opened on this folder
    │   └── .assemblyscript/            the types that tsconfig.json points at
    ├── build/                          what the server compiles .ts plugins into
    └── tools/                          the compiler: amxts-compile, wamrc, natives.txt, licenses/
README.txt

tools/ is the system's own: amxts-compile.exe and wamrc.exe on Windows. A Linux upload that loses the files' execute bit is fine: the module sets it again before it runs them.

Installing

  1. Copy the kit's addons/ over the game folder's addons/.
  2. Add the module to addons/amxmodx/configs/modules.ini, beside reapi - or alone, on plain HLDS:
    reapi
    amxts_amxx
    

    AMX Mod X finds amxts_amxx.dll or amxts_amxx_i386.so by that name. plugins.ini needs no line: the module loads what it needs itself (the host plugin).
  3. Start the server, or restart it if it runs.

The first start compiles the example and loads it. The console shows:

[amxts] compiling .../addons/amxts/plugins/hello.ts
[amxts] compiler exited with 0
[amxts] loaded hello.ts

amxts_plugins in the server's console lists the plugins and what each is doing, and how many of the callbacks the module lends plugins - for commands, timers and game events - are in use:

[amxts] 1 plugin(s): 1 running, 0 unloaded, 0 refused; 2 of 512 callback slots in use
  hello.ts  running   Hello 1.0.0  by you - An example to edit

Join the server and say /hp in chat to see the example answer.

Updating since v0.2

A server a project deploys to is updated from the project:

npx amxts upgrade

Along with the project's packages and code (upgrade), it puts the module of the new release into addons/amxmodx/modules/ - and the compiler into addons/amxts/tools/, where the server has one - keeping each old file beside it with its version (amxts_amxx.dll.0.1.0). Restart the server to load the new module. A server without a project takes the new release's kit, as when installing.

What the module writes

On every start the module lays out addons/amxts: the plugins, build and tools folders, and the files it runs plugins against - the core's API (facade.ts, natives.ts, constants.ts and the rest), imports.d.ts and tsconfig.json in plugins/, natives.txt in tools/. It writes these over every time: they belong to the module, and an edit to them is lost.

It writes hello.ts and plugins.ini (naming hello.ts) only when they are not there, and leaves them alone after that: they are yours. So a server with only the module gets the example too - but compiling it takes the kit's tools/. Without them the console says amxts-compile is missing - a .ts plugin needs the compiler beside the module, and the server runs plugins built elsewhere only.

One kit, one module
The module and the kit's other files come from one build. Put a newer module on the server together with the rest of its kit: a compiler or an API file from another build makes plugins that cannot load. A compiler of another build compiles nothing, and the console names both builds: .../plugins/hello.ts is not compiled: amxts-compile is 0.1.0+5f1c2a9e07, the module 0.2.0+1bf291c0ab - take both from the same release.

The host plugin since v0.2

The module reaches AMX Mod X - its natives, its forwards, the natives Pawn plugins register - through a plugin of its own, amxts_host.amxx, which it carries inside itself. On every start it writes the plugin into addons/amxmodx/plugins/ and names it in addons/amxmodx/configs/plugins-amxts.ini, a list AMX Mod X reads after plugins.ini; when the server stops it removes both. So the host loads after the Pawn plugins of plugins.ini, and amxx plugins lists it among them - every amxts plugin runs inside it. Neither file is to be edited or copied anywhere: they belong to the module.

The plugins

addons/amxts/plugins.ini lists the plugins the server runs, one file of addons/amxts/plugins/ per line, in the order they load. A line that starts with ; or # is left out.

; One plugin per line, as a file in plugins/.
; A .ts is compiled by the server; a .aot is loaded as it is.
myplugin.aot
hello.ts
  • A .aot is a plugin built in a project, loaded as it is. It is built for the server's system: one built for Windows does not load on Linux (the server's system).
  • A .ts is compiled by the server into addons/amxts/build/<name>.aot, and compiled again only when the source is newer, or when the build there is of another amxts.
A plugin is built for one amxts
A .aot carries the amxts it was built with, and the module loads only plugins built for its own: one from another release would call into the module in ways it does not take. Such a plugin is not loaded, the others are, and the console says which one to build again: [amxts] myplugin.aot was built for amxts 0.1.0, this is 0.2.0 - build it again (or was built for an older amxts). Updating the module, build the project again and deploy it (npx amxts build --deploy); a .ts on the server is compiled again by itself.

From a project

A project deploys to the server's addons/amxts folder, which AMXTS_SERVER names in the project's .env:

AMXTS_SERVER=D:/hlds/cstrike/addons/amxts

The server's own folder (D:/hlds), its cstrike or cstrike/addons will do too: the build takes cstrike/addons/amxts under it and names the folder it uses on the Server line of its header. A folder that is none of them stops the build with one line saying where it looked.

npx amxts build --deploy copies the built .aot files into addons/amxts/plugins/ and writes addons/amxts/plugins.ini: the modules first, then the project's plugins, and every line the build does not know after them. A plugin that exports natives also gets its include copied into addons/amxmodx/scripting/include/, for Pawn plugins compiled on the server. npx amxts dev does it on every save and reloads the server over rcon (hot reload).

Written on the server

A .ts file needs no project: put it in addons/amxts/plugins/, name it in plugins.ini, and load it with amxts_reload or the next map. From then on every save compiles it again and reloads it. A compile error goes to the server console, and to addons/amxts/build/compile.log; the plugin that failed is watched too, so saving the fix is what loads it.

Such a plugin uses what is in its folder: the core's API without an import, as in a project (auto-imports), and with an import @amxts/core/natives, @amxts/core/constants, @amxts/core/fs and files of your own. A module package, such as @amxts/menu-core, is for plugins built in a project. For an editor, open addons/amxts/plugins itself, not the server's root: its tsconfig.json is what tells the editor the types.

Compiling holds the server
The server waits while it compiles a .ts plugin, a second or two. At a map change nobody sees it; in the middle of a round the game freezes for that long. On a server people play on, deploy .aot files built in a project.

Reloading

The module looks at the plugins ten times a second. A .aot written again since it loaded, or a .ts saved and compiled without an error, restarts every amxts plugin from disk - no map change and no command. amxts_reload does the same by hand. A restart reads plugins.ini again, so a plugin added to the list loads with the next one.

One plugin since v0.2

amxts_unload shop       // stops shop.ts
amxts_load shop         // starts it again
amxts_reload shop       // starts it over from disk, compiled again if its .ts changed
amxts_load arena.ts     // a file of plugins/ the list does not name, until the map changes

A plugin is named by its line in plugins.ini, with or without .ts or .aot. amxts_unload stops it and takes back everything it registered - its timers, commands, game events, menus' callbacks and message listeners - and the plugin stays stopped until amxts_load or the next map; a reload of every plugin leaves it stopped too. amxts_reload <plugin> restarts that plugin alone, and the others run on.

A plugin whose shared module other plugins use holds what they made through it - a menu, a function they handed it. So amxts_unload refuses it while one of them runs and names them: unload those first. amxts_reload of it restarts them after it.

amxts_plugins shows each plugin as running, unloaded, or refused with the reason: it does not compile, it was built for another amxts or another system, its top level failed.

A plugin starts over
A plugin loaded again starts from its top level: what it kept in its variables is gone. What has to outlive it goes into shared player fields or Storage.

Server commands

commandwhat it does
amxts_pluginslists the plugins: file, state (running, unloaded, refused and why), name, version, author; and how many callback slots are in use
amxts_reloadreads plugins.ini again and restarts every amxts plugin from disk
amxts_reload <plugin>restarts one plugin from disk, and the plugins that use its module
amxts_unload <plugin>stops a plugin and what it registered, until amxts_load or the next map
amxts_load <plugin>starts a stopped plugin, or one of plugins/ the list does not name
amxts_tracelogs every call into a plugin, for finding what crashes the server; again to turn it off

Another plugin list

+localinfo amxts_plugins <file> on the server's command line gives the module another list, as a path from the game folder. Its plugins are the files in plugins/ beside that list, and a .ts among them is compiled into build/ beside it:

hlds.exe -game cstrike +localinfo amxts_plugins addons/amxts/myserver/plugins.ini +map de_dust2

With a list of its own the module does not lay out addons/amxts: it runs that list and leaves the rest of the install as it is. The server in Docker runs a project's dist/ this way.