@amxts/core 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/README.md +18 -23
  2. package/README.ru.md +19 -22
  3. package/as/amxts.d.ts +63 -3
  4. package/as/constants.ts +684 -116
  5. package/as/entities.ts +1905 -1364
  6. package/as/events.ts +1694 -905
  7. package/as/facade.ts +1240 -220
  8. package/as/fetch.ts +1519 -0
  9. package/as/flags.ts +159 -145
  10. package/as/hlds.ts +1071 -0
  11. package/as/hooks.ts +5226 -5379
  12. package/as/kit.ts +15 -5
  13. package/as/lib/check.ts +1 -1
  14. package/as/natives.ts +2658 -2499
  15. package/as/remote.ts +39 -15
  16. package/as/tsconfig.json +6 -2
  17. package/as/vector.ts +12 -9
  18. package/includes/order.txt +22 -29
  19. package/includes/sources.json +0 -8
  20. package/node_modules/assemblyscript/std/assembly/index.d.ts +20 -11
  21. package/package.json +29 -7
  22. package/runtime/deps/assemblyscript/dist/asc.js +86 -16
  23. package/runtime/deps/assemblyscript/dist/assemblyscript.js +29 -29
  24. package/runtime/licenses/MPL-2.0.txt +373 -0
  25. package/runtime/licenses/README.md +5 -1
  26. package/runtime/licenses/curl-COPYING +22 -0
  27. package/runtime/licenses/libssh2-COPYING +43 -0
  28. package/runtime/licenses/mbedTLS-LICENSE +553 -0
  29. package/runtime/natives.txt +108 -105
  30. package/runtime/patches/assemblyscript-0.28.20-amxts.patch +752 -296
  31. package/runtime/patches/wamr-2.4.5-amxts.patch +148 -0
  32. package/scripts/apply-docs.ts +2 -2
  33. package/scripts/auto-imports.ts +2 -2
  34. package/scripts/build-identity.ts +115 -0
  35. package/scripts/build-wasm.ts +101 -50
  36. package/scripts/check.ts +17 -3
  37. package/scripts/client-messages.ts +246 -0
  38. package/scripts/compile-pool.ts +128 -0
  39. package/scripts/compile-worker.ts +23 -0
  40. package/scripts/compile.ts +156 -59
  41. package/scripts/docker-server.ts +13 -3
  42. package/scripts/docs/as/amxts.ts +86 -0
  43. package/scripts/docs/as/facade.ts +688 -188
  44. package/scripts/docs/as/fetch.ts +805 -0
  45. package/scripts/docs/entities.ts +43 -144
  46. package/scripts/docs/events.ts +15 -26
  47. package/scripts/docs/game.ts +68 -22
  48. package/scripts/docs/messages.ts +330 -16
  49. package/scripts/editor-api.ts +101 -0
  50. package/scripts/hlds-events.ts +370 -0
  51. package/scripts/includes.ts +12 -10
  52. package/scripts/player-fields.ts +16 -15
  53. package/scripts/prebuilt.ts +65 -23
  54. package/scripts/prepare.ts +39 -28
  55. package/scripts/project.ts +120 -20
  56. package/scripts/reapi-events.ts +98 -0
  57. package/scripts/shared-modules.ts +85 -23
  58. package/scripts/source-map.ts +242 -0
  59. package/scripts/system.ts +1 -1
  60. package/scripts/typed-commands.ts +263 -0
  61. package/scripts/typed-configs.ts +23 -12
  62. package/scripts/ui.ts +3 -1
  63. package/scripts/upgrade-menus.ts +274 -0
  64. package/scripts/upgrade-names.ts +384 -0
  65. package/scripts/upgrade.ts +830 -0
  66. package/src/cli-api.mjs +37 -4
  67. package/src/system.mjs +74 -3
  68. package/src/testing/compile.ts +8 -5
  69. package/src/testing/natives.ts +199 -5
  70. package/src/testing/network.ts +531 -0
  71. package/src/testing/server.ts +565 -47
  72. package/src/testing/tables.ts +25 -0
  73. package/as/modules/http.ts +0 -184
  74. package/scripts/docs/as/modules/http.ts +0 -66
package/README.md CHANGED
@@ -25,9 +25,9 @@ plugin.
25
25
  classes, interfaces with optional fields, closures, `async`/`await` with
26
26
  `AbortSignal`.
27
27
  - **Players and entities are objects.** `player.health = 100`,
28
- `player.team == "CT"`, `player.hideHud.push("Money")`,
28
+ `player.team == "CT"`, `player.hideHud.push("money")`,
29
29
  `entity.renderMode = "additive"`.
30
- - **Events as in the DOM.** `server.addEventListener("putinserver", ...)`,
30
+ - **Events as in the DOM.** `server.addEventListener("putInServer", ...)`,
31
31
  `game.addEventListener("takeDamage", ...)` for the game's events (reapi's
32
32
  hookchains and Ham Sandwich's functions), with
33
33
  `event.preventDefault()` and an answer by `return`.
@@ -40,9 +40,8 @@ plugin.
40
40
  reloads the running server - no map change, nobody disconnected.
41
41
  - **Tests without a server.** Your plugin runs on a fake server under
42
42
  `bun test`, driven as players would drive it.
43
- - **Faster than Pawn.** Plugins are machine code by the time the server loads
44
- them; on the hot path of a real plugin that is about three times faster
45
- than the same logic in Pawn.
43
+ - **Machine code.** Plugins are compiled to machine code before the server
44
+ loads them ([performance](docs/en/2.core/05.performance.md)).
46
45
  - **Modules, one per server.** `amxts.config.ts` lists them, `amxts module add`
47
46
  installs them, and each runs once per server for every plugin that
48
47
  uses it; a module no plugin uses is not built.
@@ -55,9 +54,10 @@ On the server:
55
54
  `amxts_amxx_i386.so`, both tested on a real server. A plugin is compiled
56
55
  for its server's system, which the build reads off the server's folder
57
56
  (or `--os`).
58
- - **ReHLDS with ReGameDLL and reapi** - recommended, and what amxts is tested
59
- on. Entity fields and the game events reapi delivers need it; plain HLDS
60
- has not been tried.
57
+ - **ReHLDS with ReGameDLL and reapi** - recommended. amxts is tested on it and
58
+ on plain HLDS, where entity fields and most game events work through AMX
59
+ Mod X's own modules, and some of ReGameDLL's events come with less or not at
60
+ all.
61
61
  - **AMX Mod X 1.9** or later.
62
62
 
63
63
  To write plugins: [Node.js](https://nodejs.org) 20.12+. The build runs on
@@ -73,14 +73,6 @@ It asks for the package manager, the folder, the modules, lint and the
73
73
  server's folder, writes a project with a first plugin and its test, and
74
74
  installs everything.
75
75
 
76
- > [!WARNING]
77
- > The packages are not on npm yet. Until they are, create a project from a
78
- > clone of this repository, with [amxts-cli](https://github.com/amxts/amxts-cli)
79
- > (the `amxts` command) and the official modules cloned beside it; it links
80
- > the core and the modules instead of installing them:
81
- > `node <core>/bin/amxts.mjs init my-server --local`.
82
- > See [getting started](https://amxts.github.io/docs/getting-started/quick-start#a-project).
83
-
84
76
  Then, in the project:
85
77
 
86
78
  ```sh
@@ -95,8 +87,8 @@ npx amxts test # the tests, on a fake server
95
87
  // plugins/hello.ts
96
88
  plugin({ name: "Hello", version: "1.0.0", author: "you", description: "An example" });
97
89
 
98
- server.addCommand("/hp", sayHp);
99
- server.addEventListener("putinserver", (event) => {
90
+ server.addCommand("/hp", ({ player }) => sayHp(player));
91
+ server.addEventListener("putInServer", (event) => {
100
92
  print(0, `${event.player.name} joined`);
101
93
  });
102
94
 
@@ -118,8 +110,9 @@ official modules, kept by the amxts authors:
118
110
  | [menu-core](https://github.com/amxts/menu-core) | menus from INI, YAML or JSON files or from code: conditions, lists, countdowns - and the `mc_*` natives for Pawn plugins |
119
111
  | [config-core](https://github.com/amxts/config-core) | configs in INI, YAML or JSON, read into typed objects and written back - and the `cfg_*` natives for Pawn plugins |
120
112
  | [resemiclip](https://github.com/amxts/resemiclip) | who walks through whom, as a rule over two players, over the ReSemiclip module |
113
+ | [ftp](https://github.com/amxts/ftp) | FTP, FTPS and SFTP: upload, download and list files on another server, every call a promise |
121
114
 
122
- `fetch` over easy_http comes with the core (`~/modules/http`). More modules
115
+ Web requests come with the core: `useFetch<T>(url)` and `fetch`, as in the browser. More modules
123
116
  are in the [catalog](https://amxts.github.io/modules), and
124
117
  `npx amxts init --module` starts your own.
125
118
 
@@ -133,8 +126,10 @@ register as you type them. TypeScript itself needs nothing extra: a project's
133
126
  ## Documentation
134
127
 
135
128
  [amxts.github.io](https://amxts.github.io/) - getting started, the API,
136
- modules, testing and what amxts cannot do yet, in English and Russian. The
137
- sources are in [`docs`](docs).
129
+ modules, testing and what amxts cannot do yet, in English and Russian. It
130
+ describes the latest release; the next one, which this branch builds, is at
131
+ [amxts.github.io/docs/next](https://amxts.github.io/docs/next). The sources
132
+ are in [`docs`](docs).
138
133
 
139
134
  ## Building from source
140
135
 
@@ -157,6 +152,6 @@ send a change.
157
152
 
158
153
  ## License
159
154
 
160
- [MIT](LICENSE). The server module and the host plugin built from this code use
161
- AMX Mod X's SDK, so they are distributed under GPL-3.0-or-later. Third-party
155
+ [MIT](LICENSE). The server module built from this code, with the host plugin
156
+ it carries, uses AMX Mod X's SDK, so it is distributed under GPL-3.0-or-later. Third-party
162
157
  licenses: [`runtime/licenses`](runtime/licenses/README.md).
package/README.ru.md CHANGED
@@ -25,9 +25,9 @@ Mod X рядом с Pawn-плагинами. Они вызывают друг д
25
25
  интерфейсы с необязательными полями, замыкания, `async`/`await` с
26
26
  `AbortSignal`.
27
27
  - **Игроки и сущности — объекты.** `player.health = 100`,
28
- `player.team == "CT"`, `player.hideHud.push("Money")`,
28
+ `player.team == "CT"`, `player.hideHud.push("money")`,
29
29
  `entity.renderMode = "additive"`.
30
- - **События как в DOM.** `server.addEventListener("putinserver", ...)`,
30
+ - **События как в DOM.** `server.addEventListener("putInServer", ...)`,
31
31
  `game.addEventListener("takeDamage", ...)` для событий игры (хукчейнов
32
32
  reapi и функций Ham Sandwich), с
33
33
  `event.preventDefault()` и ответом через `return`.
@@ -41,9 +41,8 @@ Mod X рядом с Pawn-плагинами. Они вызывают друг д
41
41
  перезагружает работающий сервер — без смены карты, никого не выкидывает.
42
42
  - **Тесты без сервера.** Плагин работает на поддельном сервере под
43
43
  `bun test`, и тест ведёт его, как вели бы игроки.
44
- - **Быстрее Pawn.** К загрузке на сервер плагин уже машинный код; на горячем
45
- пути настоящего плагина это примерно в три раза быстрее той же логики на
46
- Pawn.
44
+ - **Машинный код.** Плагин компилируется в машинный код до того, как сервер
45
+ его загрузит ([производительность](docs/ru/2.core/05.performance.md)).
47
46
  - **Модули — по одному на сервер.** `amxts.config.ts` их перечисляет,
48
47
  `amxts module add` ставит, и каждый работает на сервере в одном экземпляре
49
48
  для всех плагинов, которые им пользуются; модуль, которым не пользуется
@@ -57,9 +56,10 @@ Mod X рядом с Pawn-плагинами. Они вызывают друг д
57
56
  `amxts_amxx_i386.so`, оба проверены на настоящем сервере. Плагин
58
57
  компилируется под систему своего сервера, которую сборка узнаёт по папке
59
58
  сервера (или по `--os`).
60
- - **ReHLDS с ReGameDLL и reapi** — рекомендуется, на этом amxts и
61
- проверяется. Полям сущностей нужен reapi, как и событиям игры, которые
62
- приходят от него; на обычном HLDS не запускали.
59
+ - **ReHLDS с ReGameDLL и reapi** — рекомендуется. amxts проверяется на нём и
60
+ на обычном HLDS, где поля сущностей и большинство событий игры работают через
61
+ собственные модули AMX Mod X, а часть событий ReGameDLL приходит с меньшим
62
+ или не приходит вовсе.
63
63
  - **AMX Mod X 1.9** или новее.
64
64
 
65
65
  Для разработки плагинов: [Node.js](https://nodejs.org) 20.12+. Сборка работает
@@ -74,13 +74,6 @@ npm create amxts@latest # or: pnpm create amxts, yarn create amxts, bun creat
74
74
  Команда спрашивает менеджер пакетов, папку, модули, линт и папку сервера,
75
75
  пишет проект с первым плагином и его тестом и всё устанавливает.
76
76
 
77
- > [!WARNING]
78
- > Пакетов в npm пока нет. До тех пор проект создаётся из клона этого
79
- > репозитория, рядом с которым склонированы [amxts-cli](https://github.com/amxts/amxts-cli)
80
- > (команда `amxts`) и официальные модули; он подключает ядро и модули
81
- > ссылками, а не ставит их: `node <core>/bin/amxts.mjs init my-server --local`.
82
- > Подробнее — в [начале работы](https://amxts.github.io/ru/docs/getting-started/quick-start#проект).
83
-
84
77
  Дальше, в проекте:
85
78
 
86
79
  ```sh
@@ -95,8 +88,8 @@ npx amxts test # the tests, on a fake server
95
88
  // plugins/hello.ts
96
89
  plugin({ name: "Hello", version: "1.0.0", author: "you", description: "An example" });
97
90
 
98
- server.addCommand("/hp", sayHp);
99
- server.addEventListener("putinserver", (event) => {
91
+ server.addCommand("/hp", ({ player }) => sayHp(player));
92
+ server.addEventListener("putInServer", (event) => {
100
93
  print(0, `${event.player.name} joined`);
101
94
  });
102
95
 
@@ -118,8 +111,9 @@ amxts:
118
111
  | [menu-core](https://github.com/amxts/menu-core) | меню из файлов INI, YAML или JSON или из кода: условия, списки, отсчёты — и нативы `mc_*` для Pawn-плагинов |
119
112
  | [config-core](https://github.com/amxts/config-core) | конфиги в INI, YAML или JSON, прочитанные в типизированные объекты и записанные обратно, — и нативы `cfg_*` для Pawn-плагинов |
120
113
  | [resemiclip](https://github.com/amxts/resemiclip) | кто сквозь кого проходит, правилом над двумя игроками, поверх модуля ReSemiclip |
114
+ | [ftp](https://github.com/amxts/ftp) | FTP, FTPS и SFTP: загрузка, скачивание и список файлов на другом сервере, каждый вызов — промис |
121
115
 
122
- `fetch` поверх easy_http идёт с ядром (`~/modules/http`). Другие модули — в
116
+ Веб-запросы идут с ядром: `useFetch<T>(url)` и `fetch`, как в браузере. Другие модули — в
123
117
  [каталоге](https://amxts.github.io/ru/modules), а `npx amxts init --module`
124
118
  начинает свой.
125
119
 
@@ -133,8 +127,10 @@ amxts:
133
127
  ## Документация
134
128
 
135
129
  [amxts.github.io](https://amxts.github.io/ru/) — начало работы, API, модули,
136
- тесты и то, чего amxts пока не умеет, на русском и английском. Исходники — в
137
- [`docs`](docs).
130
+ тесты и то, чего amxts пока не умеет, на русском и английском. Она описывает
131
+ последний релиз; следующий, который собирает эта ветка, — на
132
+ [amxts.github.io/ru/docs/next](https://amxts.github.io/ru/docs/next).
133
+ Исходники — в [`docs`](docs).
138
134
 
139
135
  ## Сборка из исходников
140
136
 
@@ -157,6 +153,7 @@ bun run test
157
153
 
158
154
  ## Лицензия
159
155
 
160
- [MIT](LICENSE). Модуль сервера и host-плагин, собранные из этого кода,
161
- используют SDK AMX Mod X, поэтому распространяются под GPL-3.0-or-later.
156
+ [MIT](LICENSE). Модуль сервера, собранный из этого кода, вместе с
157
+ плагином-хостом, который он несёт в себе, использует SDK AMX Mod X, поэтому
158
+ распространяется под GPL-3.0-or-later.
162
159
  Лицензии сторонних проектов: [`runtime/licenses`](runtime/licenses/README.md).
package/as/amxts.d.ts CHANGED
@@ -5,7 +5,7 @@
5
5
  // Only the editor reads this file. The build reads a module's definition from
6
6
  // its source and evaluates amxts.config.ts with a defineConfig of its own
7
7
  // (scripts/project.ts); asc never compiles either call.
8
- import type { ModuleOptions, Player, PlayerChangeEvent } from "./facade";
8
+ import type { CommandOptions, ModuleOptions, Player, PlayerChangeEvent } from "./facade";
9
9
 
10
10
  declare global {
11
11
  /** A module's name and config key. */
@@ -128,6 +128,21 @@ type PlayerFieldValue<F extends string> = F extends `${infer O}.${infer M}`
128
128
  ? O extends keyof Player ? (M extends keyof Player[O] ? Player[O][M] : never) : never
129
129
  : F extends keyof Player ? Player[F] : never;
130
130
 
131
+ // A command's arguments, typed. The build reads the type argument and the
132
+ // usage the same way (scripts/typed-commands.ts); the editor reads them here.
133
+
134
+ /** The names a usage requires: `<target>` in `"/kick <target> [reason]"`. */
135
+ type RequiredNames<U extends string> = U extends `${string}<${infer N}>${infer R}` ? N | RequiredNames<R> : never;
136
+
137
+ /** The names a usage may leave out: `[reason]`. */
138
+ type OptionalNames<U extends string> = U extends `${string}[${infer N}]${infer R}` ? N | OptionalNames<R> : never;
139
+
140
+ /** A usage's arguments, each text; any name for a usage made at run time, which the build reads. */
141
+ type UsageArgs<U extends string> = string extends U ? Record<string, string | undefined> : { [K in RequiredNames<U>]: string } & { [K in OptionalNames<U>]?: string };
142
+
143
+ /** A command's arguments: the type argument's, or else the usage's, as text. */
144
+ type CommandArgsOf<T, U extends string> = [T] extends [never] ? UsageArgs<U> : T;
145
+
131
146
  declare module "./facade" {
132
147
  interface PlayerChangeEvent<F extends string = string> {
133
148
  /** The field's value after the change; with `{ field }`, of the field's type. */
@@ -143,10 +158,55 @@ declare module "./facade" {
143
158
  * and `event.previous` have the field's type.
144
159
  */
145
160
  // oxlint-disable-next-line typescript/method-signature-style -- an overload, merged into the class's method
146
- addEventListener<F extends PlayerFieldName>(type: "playerchange", listener: (event: PlayerChangeEvent<F>) => void, options: { field: F }): void;
161
+ addEventListener<F extends PlayerFieldName>(type: "playerChange", listener: (event: PlayerChangeEvent<F>) => void, options: { field: F }): void;
147
162
  /** Stops calling a listener added with `addEventListener` - the same function and the same field. */
148
163
  // oxlint-disable-next-line typescript/method-signature-style -- an overload, merged into the class's method
149
- removeEventListener<F extends PlayerFieldName>(type: "playerchange", listener: (event: PlayerChangeEvent<F>) => void, options: { field: F }): void;
164
+ removeEventListener<F extends PlayerFieldName>(type: "playerChange", listener: (event: PlayerChangeEvent<F>) => void, options: { field: F }): void;
165
+ /**
166
+ * Adds a command players type, by its usage: the name, then the
167
+ * arguments, `<name>` required and `[name]` optional. Their types are an
168
+ * interface, the type argument; without it each is text.
169
+ *
170
+ * ```ts
171
+ * interface KickArgs {
172
+ * target: Player;
173
+ * reason?: string;
174
+ * }
175
+ *
176
+ * server.addCommand<KickArgs>("/kick <target> [reason]", ({ player, target, reason }) => {
177
+ * target.kick(reason ?? `Kicked by ${player.name}`);
178
+ * }, { access: "kick" });
179
+ * server.addCommand("/hp", ({ player }) => print(player, `${player.health} HP`));
180
+ * ```
181
+ *
182
+ * A name with `/` is a chat command, one without a console command, and
183
+ * `"say <phrase>"` a phrase written in chat. A `number` argument is
184
+ * parsed, a `Player` found by `#userid`, the whole name or a part of it,
185
+ * a `string` taken as it is - the last one takes the rest of the line. A
186
+ * word that is not what the command takes answers the player with the
187
+ * usage, and the handler does not run.
188
+ *
189
+ * Pawn: `register_clcmd`
190
+ */
191
+ // oxlint-disable-next-line typescript/method-signature-style -- the editor's signature of the class's method, which the build writes per call
192
+ addCommand<T extends object = never, const U extends string = string>(usage: U, handler: (args: CommandArgsOf<T, U> & { player: Player }) => void, options?: CommandOptions): void;
193
+ /**
194
+ * Adds a command of the server console - typed there, sent over rcon or
195
+ * run by another plugin - by its usage, its arguments read as a player's
196
+ * command's are. No player types it.
197
+ *
198
+ * ```ts
199
+ * interface ResetArgs {
200
+ * what?: "scores" | "all";
201
+ * }
202
+ *
203
+ * server.addServerCommand<ResetArgs>("myplugin_reset [what]", ({ what }) => reset(what ?? "all"));
204
+ * ```
205
+ *
206
+ * Pawn: `register_srvcmd`
207
+ */
208
+ // oxlint-disable-next-line typescript/method-signature-style -- the editor's signature of the class's method, which the build writes per call
209
+ addServerCommand<T extends object = never, const U extends string = string>(usage: U, handler: (args: CommandArgsOf<T, U>) => void): void;
150
210
  }
151
211
  }
152
212