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,cstrikeandfun. 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'sfun,cstrike,hamsandwichandfakemeta, and most game events are heard through them too, some with less (a server without ReAPI). A plugin asks withhasModule("reapi"). A project for such a server saystarget: "hlds"inamxts.config.ts(the server's includes), and a listener for an event nothing there hears does not build. - For
.tsplugins compiled on the server: a 64-bit system - Windows x64, or Linux x86-64 with glibc 2.27 or newer. A 32-bithlds_linuxruns on it as it is. A server that only runs plugins built elsewhere does not need this.
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, …),giveDefaultItemsand 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,escapeRatioandupdateInterval: they read0and write nothing, said once;timeLimitandgameStartTimeare counted frommp_timelimit; - ReAPI's own natives (
get_entvar,get_member,rg_*): a call does nothing and answers0, said once for each native.
The server kit
The kit is one archive per system, with everything that goes on the server:
| system | archive | the module |
|---|---|---|
| Windows | amxts-server-windows-x64.zip | amxts_amxx.dll |
| Linux | amxts-server-linux-x64.tar.gz | amxts_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
- Copy the kit's
addons/over the game folder'saddons/. - Add the module to
addons/amxmodx/configs/modules.ini, besidereapi- or alone, on plain HLDS:reapi amxts_amxx
AMX Mod X findsamxts_amxx.dlloramxts_amxx_i386.soby that name.plugins.inineeds no line: the module loads what it needs itself (the host plugin). - 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
pnpm amxts upgrade
yarn amxts upgrade
bunx 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.
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
.aotis 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
.tsis compiled by the server intoaddons/amxts/build/<name>.aot, and compiled again only when the source is newer, or when the build there is of another 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.
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 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
| command | what it does |
|---|---|
amxts_plugins | lists the plugins: file, state (running, unloaded, refused and why), name, version, author; and how many callback slots are in use |
amxts_reload | reads 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_trace | logs 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.
CLI
amxts is the command a project runs: it creates projects and modules, adds modules, builds, deploys, type-checks and tests. It is the package @amxts/cli, which @amxts/core depends on, so every project has it and runs it through its package manager:
A server in Docker
ghcr.io/amxts/server is a Docker image of a Linux Counter-Strike 1.6 server that runs amxts: HLDS with ReHLDS, ReGameDLL, Metamod-R, AMX Mod X 1.10 and ReAPI, the amxts module and its compiler. Your project is mounted into it, and the server runs your plugins with your configs and files - on Windows, macOS or Linux, with nothing to install but Docker.