@amxts/core 0.2.0 → 0.2.2

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.
package/README.md CHANGED
@@ -28,10 +28,10 @@ plugin.
28
28
  `player.team == "CT"`, `player.hideHud.push("money")`,
29
29
  `entity.renderMode = "additive"`.
30
30
  - **Events as in the DOM.** `server.addEventListener("putInServer", ...)`,
31
- `game.addEventListener("takeDamage", ...)` for the game's events (reapi's
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`.
34
- - **The editor knows the game.** Every native, reapi field and hookchain
34
+ - **The editor knows the game.** Every native, ReAPI field and hookchain
35
35
  comes with its type and a tooltip in English or Russian; a typo is a red
36
36
  line, not a runtime error.
37
37
  - **No import lines.** `Player`, `server`, `print` and the modules' names are
@@ -54,10 +54,11 @@ On the server:
54
54
  `amxts_amxx_i386.so`, both tested on a real server. A plugin is compiled
55
55
  for its server's system, which the build reads off the server's folder
56
56
  (or `--os`).
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.
57
+ - **ReHLDS with ReGameDLL and ReAPI** - recommended. amxts is tested on it and
58
+ on plain HLDS, where the entity fields work through AMX Mod X's own modules
59
+ and the game events come through Ham Sandwich, the game's log and its
60
+ messages: most of them after the game has acted, and a few of ReGameDLL's
61
+ not at all.
61
62
  - **AMX Mod X 1.9** or later.
62
63
 
63
64
  To write plugins: [Node.js](https://nodejs.org) 20.12+. The build runs on
package/README.ru.md CHANGED
@@ -29,9 +29,9 @@ Mod X рядом с Pawn-плагинами. Они вызывают друг д
29
29
  `entity.renderMode = "additive"`.
30
30
  - **События как в DOM.** `server.addEventListener("putInServer", ...)`,
31
31
  `game.addEventListener("takeDamage", ...)` для событий игры (хукчейнов
32
- reapi и функций Ham Sandwich), с
32
+ ReAPI и функций Ham Sandwich), с
33
33
  `event.preventDefault()` и ответом через `return`.
34
- - **Редактор знает игру.** Каждый натив, поле reapi и хукчейн — с типом и
34
+ - **Редактор знает игру.** Каждый натив, поле ReAPI и хукчейн — с типом и
35
35
  подсказкой на русском или английском; опечатка — красная строка, а не
36
36
  ошибка на сервере.
37
37
  - **Без строк импорта.** `Player`, `server`, `print` и имена модулей
@@ -56,10 +56,11 @@ Mod X рядом с Pawn-плагинами. Они вызывают друг д
56
56
  `amxts_amxx_i386.so`, оба проверены на настоящем сервере. Плагин
57
57
  компилируется под систему своего сервера, которую сборка узнаёт по папке
58
58
  сервера (или по `--os`).
59
- - **ReHLDS с ReGameDLL и reapi** — рекомендуется. amxts проверяется на нём и
60
- на обычном HLDS, где поля сущностей и большинство событий игры работают через
61
- собственные модули AMX Mod X, а часть событий ReGameDLL приходит с меньшим
62
- или не приходит вовсе.
59
+ - **ReHLDS с ReGameDLL и ReAPI** — рекомендуется. amxts проверяется на нём и
60
+ на обычном HLDS, где поля сущностей работают через собственные модули AMX
61
+ Mod X, а события игры приходят через Ham Sandwich, лог игры и её сообщения:
62
+ большинство — когда игра уже сделала своё, а некоторые события ReGameDLL не
63
+ приходят вовсе.
63
64
  - **AMX Mod X 1.9** или новее.
64
65
 
65
66
  Для разработки плагинов: [Node.js](https://nodejs.org) 20.12+. Сборка работает
package/as/events.ts CHANGED
@@ -68,7 +68,7 @@ export class ServerChangelevelEvent {
68
68
  }
69
69
 
70
70
  /**
71
- * Every config has been read and every plugin is loaded: the moment to read cvars and to create forwards other plugins listen to.
71
+ * Every plugin has started: the moment to create forwards other plugins listen to. The configs run after it: read cvars in `"configsExecuted"`.
72
72
  *
73
73
  * Note: When this forward is called, most plugins should have registered their cvars and commands already.
74
74
  *
@@ -2255,7 +2255,7 @@ export interface ServerEventMap {
2255
2255
  */
2256
2256
  changeLevel: ServerChangelevelEvent;
2257
2257
  /**
2258
- * Every config has been read and every plugin is loaded: the moment to read cvars and to create forwards other plugins listen to.
2258
+ * Every plugin has started: the moment to create forwards other plugins listen to. The configs run after it: read cvars in `"configsExecuted"`.
2259
2259
  *
2260
2260
  * Pawn: `plugin_cfg`
2261
2261
  */
package/as/tsconfig.json CHANGED
@@ -3,6 +3,7 @@
3
3
  "compilerOptions": {
4
4
  "target": "es2015",
5
5
  "moduleDetection": "force",
6
+ "useUnknownInCatchVariables": false,
6
7
  "module": "esnext",
7
8
  "moduleResolution": "bundler",
8
9
  "paths": {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@amxts/core",
3
3
  "type": "module",
4
- "version": "0.2.0",
4
+ "version": "0.2.2",
5
5
  "description": "Counter-Strike 1.6 plugins in TypeScript: compiled ahead of time and run inside AMX Mod X, next to Pawn plugins.",
6
6
  "author": {
7
7
  "name": "kukson777",
@@ -104,12 +104,12 @@
104
104
  "assemblyscript": "0.28.20"
105
105
  },
106
106
  "optionalDependencies": {
107
- "@amxts/wamrc-linux-x64": "^0.2.0",
108
- "@amxts/wamrc-win32-x64": "^0.2.0"
107
+ "@amxts/wamrc-linux-x64": "^0.2.2",
108
+ "@amxts/wamrc-win32-x64": "^0.2.2"
109
109
  },
110
110
  "devDependencies": {
111
- "@amxts/config-core": "^0.1.1",
112
- "@amxts/menu-core": "^0.2.0",
111
+ "@amxts/config-core": "^0.1.2",
112
+ "@amxts/menu-core": "^0.2.1",
113
113
  "@e18e/eslint-plugin": "^0.8.1",
114
114
  "@eslint-community/eslint-plugin-eslint-comments": "^4.8.1",
115
115
  "@stylistic/eslint-plugin": "^5.10.0",
@@ -1,7 +1,8 @@
1
1
  // Compiles kept on disk, reused while what they read is the same.
2
2
  //
3
3
  // A compile is keyed by everything that is not a file it read - the
4
- // compiler, the hood's scripts, the flags, the project and its config - and
4
+ // compiler, the hood's scripts, the version the core builds as (a plugin
5
+ // carries it in its ABI), the flags, the project and its config - and
5
6
  // stored with every file read it made (scripts/tracked-fs.ts): the entry, what
6
7
  // it imports, the facade and the generated API, the module packages. It is
7
8
  // taken again only while each of those reads sees the same thing it saw, so a
@@ -15,6 +16,7 @@ import type { Reads } from './tracked-fs';
15
16
  import { existsSync, mkdirSync, readdirSync, readFileSync, renameSync, rmSync, statSync, writeFileSync } from 'node:fs';
16
17
  import { dirname, join, resolve } from 'node:path';
17
18
  import { fileURLToPath } from 'node:url';
19
+ import { coreVersion } from './build-identity';
18
20
  import { listIncludes } from './includes';
19
21
  import { currentProjectDir, loadProject } from './project';
20
22
  import { hashOf, recordReads, unchanged } from './tracked-fs';
@@ -118,7 +120,7 @@ export function diskCache(dir: string | null, code: () => string, ownIncludes: s
118
120
  let identity: string | null = null;
119
121
  const fileOf = (parts: unknown[]) => {
120
122
  identity ??= hashOf(`${FORMAT}\n${code()}`);
121
- return join(dir!, `${hashOf(JSON.stringify([identity, projectIdentity(ownIncludes), ...parts]))}.json`);
123
+ return join(dir!, `${hashOf(JSON.stringify([identity, coreVersion(), projectIdentity(ownIncludes), ...parts]))}.json`);
122
124
  };
123
125
 
124
126
  let pruned = false;
@@ -53,8 +53,8 @@ export const EVENTS: Record<string, EventDoc> = {
53
53
  },
54
54
  plugin_cfg: {
55
55
  summary: {
56
- en: `Every config has been read and every plugin is loaded: the moment to read cvars and to create forwards other plugins listen to.`,
57
- ru: `Все конфиги прочитаны, все плагины загружены: момент читать квары и создавать форварды для других плагинов.`,
56
+ en: `Every plugin has started: the moment to create forwards other plugins listen to. The configs run after it: read cvars in \`"configsExecuted"\`.`,
57
+ ru: `Все плагины запустились: момент создавать форварды для других плагинов. Конфиги выполняются после него: квары читайте в \`"configsExecuted"\`.`,
58
58
  },
59
59
  },
60
60
  plugin_end: {
@@ -115,6 +115,9 @@ const tsconfig = {
115
115
  // plugin declares is its own, never a global another plugin's name
116
116
  // collides with.
117
117
  moduleDetection: 'force',
118
+ // `catch (error)` reads `error.message` as the compiler takes it: the
119
+ // base config's strict mode would make the caught value `unknown`.
120
+ useUnknownInCatchVariables: false,
118
121
  paths,
119
122
  },
120
123
  include: [
@@ -30,11 +30,12 @@ import type { Kind } from './upgrade-names';
30
30
  // with its title (scripts/upgrade-menus.ts). What is rewritten no longer
31
31
  // matches, so a second run changes nothing.
32
32
  import { existsSync, readdirSync, readFileSync, writeFileSync } from 'node:fs';
33
- import { join, relative, resolve } from 'node:path';
33
+ import { basename, dirname, join, relative, resolve } from 'node:path';
34
34
  import { fileURLToPath } from 'node:url';
35
35
  import ts from 'typescript';
36
36
  import { MESSAGE_NAMES } from './client-messages';
37
37
  import { CORE_ENTRIES, CORE_PLUGINS, loadProject } from './project';
38
+ import { apiFiles, serverFolder } from './system';
38
39
  import { c, log } from './ui';
39
40
  import { upgradeMenus } from './upgrade-menus';
40
41
  import { COMMON, EVENTS, FLAG_NAMES, GAME_EVENT_FIELDS, HIDDEN, HIDDEN_EVENTS, JOIN_OPTIONS, RENAMED, SERVER_EVENT_CLASSES, SERVER_EVENT_FIELDS, SERVER_EVENTS, SERVER_EVENTS_BY_HAND, SERVER_FIELD_CLASSES, SERVER_GAME_EVENTS } from './upgrade-names';
@@ -774,15 +775,41 @@ export function upgradeFlags(file: string, text: string): { text: string; change
774
775
  /** Folders that are not the project's code: what is installed, built or generated. */
775
776
  const SKIP = new Set(['node_modules', 'dist', '.amxts', '.git']);
776
777
 
778
+ /** A server's addons/amxts: the module's files, written over on every start. */
779
+ const SERVER_FOLDER = /[\\/]addons[\\/]amxts$/i;
780
+
777
781
  /** The project's TypeScript files: its plugins, its tests and fixtures, a module's sources. */
778
782
  function codeFiles(dir: string, skip: Set<string>): string[] {
779
783
  return readdirSync(dir, { withFileTypes: true }).flatMap((entry) => {
780
784
  const path = join(dir, entry.name);
781
- if (entry.isDirectory()) return SKIP.has(entry.name) || skip.has(path) || entry.name.startsWith('.') ? [] : codeFiles(path, skip);
785
+ if (entry.isDirectory()) return SKIP.has(entry.name) || skip.has(path) || entry.name.startsWith('.') || SERVER_FOLDER.test(path) ? [] : codeFiles(path, skip);
782
786
  return /\.(?:ts|mts|cts)$/.test(entry.name) ? [path] : [];
783
787
  });
784
788
  }
785
789
 
790
+ /** The server's addons/amxts that AMXTS_SERVER names, or '' when it names none. */
791
+ function serverDir(): string {
792
+ try {
793
+ const dir = serverFolder(process.env.AMXTS_SERVER ?? '');
794
+ return dir && resolve(dir);
795
+ } catch {
796
+ return '';
797
+ }
798
+ }
799
+
800
+ /**
801
+ * The project's code to upgrade. The module's own files - the API a server
802
+ * writes beside its plugins, at the core's version it runs - are not, in the
803
+ * server's folder or a copy of one; a file of that name in the plugins
804
+ * folder is the author's.
805
+ */
806
+ function projectFiles(dir: string, pluginsDir: string, outDir: string): string[] {
807
+ // The API at the top of as/, and the editor's globals: what the module
808
+ // writes beside the plugins (scripts/server-files.ts).
809
+ const theirs = new Set([...apiFiles(), 'imports.d.ts']);
810
+ return codeFiles(dir, new Set([outDir, serverDir()])).filter(file => !theirs.has(basename(file)) || dirname(file) === pluginsDir);
811
+ }
812
+
786
813
  /** Rewrites the project in `dir`: every change, in the order of the files, and what is left to do by hand. `write: false` only lists them. */
787
814
  export function upgradeProject(dir: string, { write = true } = {}): { changes: Change[]; left: Left[] } {
788
815
  const project = loadProject(dir);
@@ -790,7 +817,7 @@ export function upgradeProject(dir: string, { write = true } = {}): { changes: C
790
817
  const renames = renamesFor(project.modules, place => ownFolder && existsSync(join(project.pluginsDir, place)));
791
818
  const changes: Change[] = [];
792
819
  const left: Left[] = [];
793
- for (const file of codeFiles(project.dir, new Set([project.outDir]))) {
820
+ for (const file of projectFiles(project.dir, resolve(project.pluginsDir), project.outDir)) {
794
821
  const text = readFileSync(file, 'utf8');
795
822
  const name = relative(project.dir, file).replace(/\\/g, '/');
796
823
  const http = dropHttpImports(name, text);
@@ -26,7 +26,8 @@ export { constant } from './tables';
26
26
 
27
27
  /**
28
28
  * Compiles a plugin (once per test run), loads it into a new fake server and
29
- * starts the map: its top level runs, then plugin_init and plugin_cfg.
29
+ * starts the map: its top level runs, then plugin_init, plugin_cfg and
30
+ * OnConfigsExecuted.
30
31
  *
31
32
  * Several plugins go into one server as an array - they hear each other's
32
33
  * forwards and natives, as on a real one.
@@ -826,11 +826,17 @@ export class FakeServer {
826
826
  return plugin;
827
827
  }
828
828
 
829
- /** plugin_precache, plugin_init and plugin_cfg, as a map start sends them. */
829
+ /**
830
+ * What a map start sends, in AMX Mod X's order: plugin_precache,
831
+ * plugin_init, plugin_cfg, then OnAutoConfigsBuffered and
832
+ * OnConfigsExecuted, once the server has run its configs.
833
+ */
830
834
  start(): void {
831
835
  this.fire('plugin_precache');
832
836
  this.fire('plugin_init');
833
837
  this.fire('plugin_cfg');
838
+ this.fire('OnAutoConfigsBuffered');
839
+ this.fire('OnConfigsExecuted');
834
840
  }
835
841
 
836
842
  // ------------------------------------------------------------ what a test reads
@@ -27,7 +27,7 @@ export interface SetupOptions extends ServerOptions {
27
27
  * `["welcome"]` - in this order; all of them when left out, none for `[]`.
28
28
  */
29
29
  plugins?: string[];
30
- /** Starts the map - plugin_init, then plugin_cfg - once everything is loaded. True when left out. */
30
+ /** Starts the map - plugin_init, plugin_cfg, then OnConfigsExecuted - once everything is loaded. True when left out. */
31
31
  start?: boolean;
32
32
  }
33
33