@pkmn/engine 0.1.0-dev.fb5bf955 → 0.1.0-dev.fb6653d6

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 (85) hide show
  1. package/LICENSE +1 -3
  2. package/README.md +115 -76
  3. package/build/pkg/addon/browser.d.ts +3 -0
  4. package/build/pkg/addon/browser.js +44 -0
  5. package/build/pkg/addon/browser.js.map +1 -0
  6. package/build/pkg/addon/node.d.ts +3 -0
  7. package/build/pkg/addon/node.js +97 -0
  8. package/build/pkg/addon/node.js.map +1 -0
  9. package/build/pkg/addon/wasm.d.ts +2 -0
  10. package/build/pkg/addon/wasm.js +53 -0
  11. package/build/pkg/addon/wasm.js.map +1 -0
  12. package/build/pkg/addon.d.ts +27 -5
  13. package/build/pkg/addon.js +42 -73
  14. package/build/pkg/addon.js.map +1 -1
  15. package/build/pkg/data/ids.json +12 -12
  16. package/build/pkg/data/layout.json +40 -5
  17. package/build/pkg/data/protocol.json +84 -13
  18. package/build/pkg/data.d.ts +27 -5
  19. package/build/pkg/data.js.map +1 -1
  20. package/build/pkg/gen1.d.ts +16 -19
  21. package/build/pkg/gen1.js +54 -42
  22. package/build/pkg/gen1.js.map +1 -1
  23. package/build/pkg/index.d.ts +55 -103
  24. package/build/pkg/index.js +6 -63
  25. package/build/pkg/index.js.map +1 -1
  26. package/build/pkg/protocol.d.ts +24 -3
  27. package/build/pkg/protocol.js +127 -104
  28. package/build/pkg/protocol.js.map +1 -1
  29. package/build/tools/debug.js +36 -69
  30. package/build/tools/debug.js.map +1 -1
  31. package/build/tools/display/debug.jsx +141 -0
  32. package/build/tools/display/debug.jsx.map +1 -0
  33. package/build/tools/display/index.js +142 -0
  34. package/build/tools/display/index.js.map +1 -0
  35. package/build/tools/display/ui.jsx +349 -0
  36. package/build/tools/display/ui.jsx.map +1 -0
  37. package/build/tools/display/util.js +18 -0
  38. package/build/tools/display/util.js.map +1 -0
  39. package/build.zig +373 -152
  40. package/package.json +68 -120
  41. package/src/bin/install-pkmn-engine +41 -26
  42. package/src/bin/pkmn-debug +29 -6
  43. package/src/lib/bindings/node.zig +121 -0
  44. package/src/lib/bindings/wasm.zig +58 -0
  45. package/src/lib/common/array.zig +77 -0
  46. package/src/lib/common/battle.zig +17 -0
  47. package/src/lib/common/data.zig +19 -31
  48. package/src/lib/common/debug.zig +58 -17
  49. package/src/lib/common/js.zig +120 -0
  50. package/src/lib/common/optional.zig +71 -0
  51. package/src/lib/common/options.zig +18 -3
  52. package/src/lib/common/protocol.zig +947 -407
  53. package/src/lib/common/rational.zig +449 -0
  54. package/src/lib/common/rng.zig +31 -24
  55. package/src/lib/common/util.zig +61 -0
  56. package/src/lib/gen1/calc.zig +953 -0
  57. package/src/lib/gen1/chance.zig +1185 -0
  58. package/src/lib/gen1/data/moves.zig +203 -193
  59. package/src/lib/gen1/data/species.zig +6 -8
  60. package/src/lib/gen1/data/types.zig +11 -12
  61. package/src/lib/gen1/data.zig +100 -89
  62. package/src/lib/gen1/helpers.zig +139 -50
  63. package/src/lib/gen1/mechanics.zig +1344 -907
  64. package/src/lib/gen2/calc.zig +153 -0
  65. package/src/lib/gen2/chance.zig +902 -0
  66. package/src/lib/gen2/data/items.zig +15 -23
  67. package/src/lib/gen2/data/moves.zig +665 -573
  68. package/src/lib/gen2/data/species.zig +3 -5
  69. package/src/lib/gen2/data/types.zig +138 -36
  70. package/src/lib/gen2/data.zig +134 -99
  71. package/src/lib/gen2/generated.zig +801 -0
  72. package/src/lib/gen2/helpers.zig +59 -44
  73. package/src/lib/gen2/mechanics.zig +3582 -30
  74. package/src/lib/node.zig +18 -0
  75. package/src/lib/pkmn.zig +93 -12
  76. package/src/lib/wasm.zig +17 -0
  77. package/src/tools/display/dom.ts +96 -0
  78. package/src/tools/display/ui.css +354 -0
  79. package/build/test/display.js +0 -382
  80. package/build/test/display.js.map +0 -1
  81. package/src/lib/binding/node.zig +0 -229
  82. package/src/lib/binding/wasm.zig +0 -10
  83. package/src/lib/gen1/README.md +0 -784
  84. package/src/lib/gen2/README.md +0 -309
  85. package/src/test/display/pkmn.html.tmpl +0 -368
package/package.json CHANGED
@@ -1,19 +1,31 @@
1
1
  {
2
2
  "name": "@pkmn/engine",
3
- "version": "0.1.0-dev.fb5bf955",
3
+ "version": "0.1.0-dev.fb6653d6",
4
4
  "description": "A minimal, complete, Pokémon battle simulation engine optimized for performance",
5
5
  "repository": "github:pkmn/engine",
6
6
  "license": "MIT",
7
7
  "sideEffects": false,
8
8
  "main": "build/pkg/index.js",
9
9
  "types": "build/pkg/index.d.ts",
10
+ "browser": {
11
+ "./build/pkg/addon/node.js": "./build/pkg/addon/browser.js"
12
+ },
10
13
  "files": [
11
14
  "build.zig",
12
- "build/pkg/data.d.ts",
13
- "build/pkg/data.js.map",
14
15
  "build/pkg/addon.d.ts",
15
16
  "build/pkg/addon.js.map",
16
17
  "build/pkg/addon.js",
18
+ "build/pkg/addon/browser.d.ts",
19
+ "build/pkg/addon/browser.js.map",
20
+ "build/pkg/addon/browser.js",
21
+ "build/pkg/addon/node.d.ts",
22
+ "build/pkg/addon/node.js.map",
23
+ "build/pkg/addon/node.js",
24
+ "build/pkg/addon/wasm.d.ts",
25
+ "build/pkg/addon/wasm.js.map",
26
+ "build/pkg/addon/wasm.js",
27
+ "build/pkg/data.d.ts",
28
+ "build/pkg/data.js.map",
17
29
  "build/pkg/data.js",
18
30
  "build/pkg/data/ids.json",
19
31
  "build/pkg/data/layout.json",
@@ -27,33 +39,52 @@
27
39
  "build/pkg/protocol.d.ts",
28
40
  "build/pkg/protocol.js.map",
29
41
  "build/pkg/protocol.js",
30
- "build/test/display.js.map",
31
- "build/test/display.js",
32
42
  "build/tools/debug.js.map",
33
43
  "build/tools/debug.js",
34
- "src/bin/install-pkmn-engine",
35
- "src/lib/binding/node.zig",
36
- "src/lib/binding/wasm.zig",
44
+ "build/tools/display/index.js.map",
45
+ "build/tools/display/index.js",
46
+ "build/tools/display/debug.jsx.map",
47
+ "build/tools/display/debug.jsx",
48
+ "build/tools/display/ui.jsx.map",
49
+ "build/tools/display/ui.jsx",
50
+ "build/tools/display/util.js.map",
51
+ "build/tools/display/util.js",
52
+ "src/lib/bindings/node.zig",
53
+ "src/lib/bindings/wasm.zig",
54
+ "src/lib/common/array.zig",
55
+ "src/lib/common/battle.zig",
37
56
  "src/lib/common/data.zig",
38
57
  "src/lib/common/debug.zig",
58
+ "src/lib/common/js.zig",
59
+ "src/lib/common/optional.zig",
39
60
  "src/lib/common/options.zig",
40
61
  "src/lib/common/protocol.zig",
62
+ "src/lib/common/rational.zig",
41
63
  "src/lib/common/rng.zig",
64
+ "src/lib/common/util.zig",
65
+ "src/lib/gen1/calc.zig",
66
+ "src/lib/gen1/chance.zig",
42
67
  "src/lib/gen1/data.zig",
43
68
  "src/lib/gen1/data/moves.zig",
44
69
  "src/lib/gen1/data/species.zig",
45
70
  "src/lib/gen1/data/types.zig",
46
71
  "src/lib/gen1/helpers.zig",
47
72
  "src/lib/gen1/mechanics.zig",
73
+ "src/lib/gen2/calc.zig",
74
+ "src/lib/gen2/chance.zig",
48
75
  "src/lib/gen2/data.zig",
49
76
  "src/lib/gen2/data/items.zig",
50
77
  "src/lib/gen2/data/moves.zig",
51
78
  "src/lib/gen2/data/species.zig",
52
79
  "src/lib/gen2/data/types.zig",
80
+ "src/lib/gen2/generated.zig",
53
81
  "src/lib/gen2/helpers.zig",
54
82
  "src/lib/gen2/mechanics.zig",
83
+ "src/lib/node.zig",
55
84
  "src/lib/pkmn.zig",
56
- "src/test/display/pkmn.html.tmpl"
85
+ "src/lib/wasm.zig",
86
+ "src/tools/display/dom.ts",
87
+ "src/tools/display/ui.css"
57
88
  ],
58
89
  "engines": {
59
90
  "node": ">=16.0.0"
@@ -66,137 +97,54 @@
66
97
  "access": "public"
67
98
  },
68
99
  "dependencies": {
69
- "@pkmn/data": "^0.7.36",
70
- "@pkmn/protocol": "^0.6.11"
100
+ "@pkmn/data": "^0.9.20",
101
+ "@pkmn/protocol": "^0.6.27"
71
102
  },
72
103
  "devDependencies": {
73
- "@pkmn/eslint-config": "^3.0.0",
74
- "@pkmn/img": "^0.2.8",
75
- "@pkmn/sets": "^5.0.4",
76
- "@pkmn/sim": "0.7.36",
77
- "@types/html-minifier": "^4.0.2",
78
- "@types/jest": "^29.5.0",
79
- "@types/minimist": "^1.2.2",
80
- "@types/mustache": "^4.2.2",
81
- "@types/node": "^18.15.11",
82
- "@vitest/coverage-c8": "^0.29.8",
83
- "binaryen": "^112.0.0",
84
- "eslint": "^8.37.0",
104
+ "@pkmn/eslint-config": "^9.0.0",
105
+ "@pkmn/img": "^0.2.32",
106
+ "@pkmn/sets": "^5.1.2",
107
+ "@pkmn/sim": "0.9.20",
108
+ "@pkmn/smogon": "^0.5.14",
109
+ "@types/html-minifier": "^4.0.5",
110
+ "@types/jest": "^29.5.13",
111
+ "@types/minimist": "^1.2.5",
112
+ "@types/mustache": "^4.2.5",
113
+ "@types/node": "^22.7.6",
114
+ "@types/react": "^18.3.11",
115
+ "@types/semver": "^7.5.8",
116
+ "@types/vscode": "^1.94.0",
117
+ "@vitest/coverage-v8": "^2.1.3",
118
+ "@vscode/vsce": "^3.2.0",
119
+ "binaryen": "^119.0.0",
120
+ "esbuild": "^0.24.0",
121
+ "eslint": "^9.12.0",
85
122
  "html-minifier": "^4.0.0",
86
123
  "json-stringify-pretty-compact": "3.0.0",
87
124
  "minimist": "^1.2.8",
88
125
  "mustache": "^4.2.0",
126
+ "semver": "^7.6.3",
89
127
  "source-map-support": "^0.5.21",
128
+ "table": "^6.8.2",
90
129
  "trakr": "^0.2.0",
91
- "typescript": "^5.0.3",
92
- "vitest": "^0.29.8"
130
+ "typescript": "^5.6.3",
131
+ "vitest": "^2.1.3"
93
132
  },
94
133
  "scripts": {
95
- "lint": "eslint --cache src --ext ts,js && eslint src/bin/*",
96
- "fix": "eslint --fix src --ext ts,js && eslint --fix src/bin/*",
134
+ "lint": "eslint --cache src",
135
+ "fix": "eslint --fix src",
97
136
  "compile": "tsc -p .",
98
137
  "build": "npm run compile",
99
138
  "test": "vitest src/pkg",
100
139
  "test:integration": "vitest src/test",
101
140
  "debug": "npm run compile && node build/tools/debug",
141
+ "demo": "npm run compile && node build/tools/demo",
102
142
  "fuzz": "npm run compile && node build/test/fuzz",
103
143
  "generate": "npm run compile && node build/tools/generate",
104
144
  "release": "npm run compile && node build/tools/release",
105
145
  "benchmark": "npm run compile && node build/test/benchmark",
106
146
  "integration": "npm run compile && node build/test/integration",
147
+ "extension": "npm -C src/tools/vscode run build",
107
148
  "postinstall": "node src/bin/install-pkmn-engine"
108
- },
109
- "eslintConfig": {
110
- "extends": "@pkmn",
111
- "ignorePatterns": [
112
- "dist/",
113
- "node_modules/",
114
- "src/examples/zig",
115
- "build/"
116
- ],
117
- "env": {
118
- "es6": true,
119
- "node": true,
120
- "browser": true
121
- },
122
- "overrides": [
123
- {
124
- "files": [
125
- "**/*.ts"
126
- ],
127
- "parserOptions": {
128
- "project": [
129
- "./tsconfig.json",
130
- "./src/examples/js/tsconfig.json"
131
- ]
132
- }
133
- },
134
- {
135
- "files": [
136
- "src/pkg/index.ts",
137
- "src/test/display.ts",
138
- "src/test/integration.ts"
139
- ],
140
- "rules": {
141
- "no-control-regex": "off",
142
- "@typescript-eslint/no-empty-interface": "off",
143
- "@typescript-eslint/no-shadow": "off"
144
- }
145
- },
146
- {
147
- "files": [
148
- "src/pkg/addon.ts"
149
- ],
150
- "rules": {
151
- "@typescript-eslint/no-var-requires": "off"
152
- }
153
- },
154
- {
155
- "files": [
156
- "src/test/benchmark*.ts"
157
- ],
158
- "rules": {
159
- "@typescript-eslint/no-unused-vars": "off"
160
- }
161
- },
162
- {
163
- "files": [
164
- "src/test/*.test.ts"
165
- ],
166
- "rules": {
167
- "jest/no-standalone-expect": "off"
168
- }
169
- },
170
- {
171
- "files": [
172
- "src/test/showdown/**"
173
- ],
174
- "rules": {
175
- "jest/expect-expect": [
176
- "warn",
177
- {
178
- "assertFunctionNames": [
179
- "expect",
180
- "expectLog",
181
- "verify"
182
- ]
183
- }
184
- ]
185
- }
186
- },
187
- {
188
- "files": [
189
- "src/tools/generate.ts"
190
- ],
191
- "rules": {
192
- "@typescript-eslint/restrict-template-expressions": [
193
- "error",
194
- {
195
- "allowBoolean": true
196
- }
197
- ]
198
- }
199
- }
200
- ]
201
149
  }
202
150
  }
@@ -10,7 +10,7 @@ const path = require('path');
10
10
  const {pipeline} = require('stream/promises');
11
11
  const tty = require('tty');
12
12
 
13
- const ZIG_VERSION = {major: 0, minor: 11, patch: 0, dev: 2168};
13
+ const ZIG_VERSION = {major: 0, minor: 11, patch: 0};
14
14
  const DEV = ZIG_VERSION.dev ? `-dev.${ZIG_VERSION.dev}` : '';
15
15
  const VERSION = `${ZIG_VERSION.major}.${ZIG_VERSION.minor}.${ZIG_VERSION.patch}${DEV}`;
16
16
  const INDEX = 'https://ziglang.org/download/index.json';
@@ -163,8 +163,10 @@ const install = async () => {
163
163
  }
164
164
 
165
165
  const index = JSON.parse(await fetch(INDEX));
166
- const version = Object.keys(index)[+!ZIG_VERSION.dev];
167
- const release = index[version][`${arch}-${platform}`];
166
+ // TODO: ziglang/zig#17768
167
+ // const version = Object.keys(index)[+!ZIG_VERSION.dev];
168
+ const version = VERSION;
169
+ const release = index[VERSION][`${arch}-${platform}`];
168
170
  const url = release.tarball;
169
171
 
170
172
  let base = path.basename(url);
@@ -255,7 +257,7 @@ const downloadImportLib = async () => {
255
257
  }
256
258
 
257
259
  const dir = path.join(ROOT, 'build', 'lib');
258
- const url = new URL('./win-x64/node.lib', process.release.headersUrl).href;
260
+ const url = process.release.libUrl;
259
261
  const dest = path.join(dir, path.basename(url));
260
262
  if (fs.existsSync(path.join(dest))) {
261
263
  log('Node import library:', dest);
@@ -283,19 +285,19 @@ const downloadImportLib = async () => {
283
285
  let error = false;
284
286
  for (let i = 2; i < process.argv.length; i++) {
285
287
  switch (process.argv[i]) {
286
- case "--silent": {
287
- SILENT = true;
288
- break;
289
- }
290
- case "--zig": {
291
- if (options || only) error = true;
292
- only = true;
293
- break;
294
- }
295
- default: {
296
- if (options || only || !process.argv[i].startsWith('--options=')) error = true;
297
- options = process.argv[i].slice(10).split(' ');
298
- }
288
+ case "--silent": {
289
+ SILENT = true;
290
+ break;
291
+ }
292
+ case "--zig": {
293
+ if (options || only) error = true;
294
+ only = true;
295
+ break;
296
+ }
297
+ default: {
298
+ if (options || only || !process.argv[i].startsWith('--options=')) error = true;
299
+ options = process.argv[i].slice(10).split(' ');
300
+ }
299
301
  }
300
302
  }
301
303
  if (error) {
@@ -336,14 +338,18 @@ const downloadImportLib = async () => {
336
338
  node = true;
337
339
  if (!options) {
338
340
  const addon = require(copy);
339
- if (addon.options.showdown) opts.push('-Dshowdown');
340
- if (addon.options.trace) opts.push('-Dtrace');
341
+ if (addon.engine.options.showdown) opts.push('-Dshowdown');
342
+ if (addon.engine.options.log) opts.push('-Dlog');
343
+ if (addon.engine.options.chance) opts.push('-Dchance');
344
+ if (addon.engine.options.calc) opts.push('-Dcalc');
341
345
  }
342
346
  } else if (!options) {
343
347
  const addon = await WebAssembly.instantiate(fs.readFileSync(copy));
344
348
  const values = new Uint8Array(addon.instance.exports.memory.buffer);
345
349
  if (values[addon.instance.exports.SHOWDOWN.value]) opts.push('-Dshowdown');
346
- if (values[addon.instance.exports.TRACE.value]) opts.push('-Dtrace');
350
+ if (values[addon.instance.exports.LOG.value]) opts.push('-Dlog');
351
+ if (values[addon.instance.exports.CHANCE.value]) opts.push('-Dchance');
352
+ if (values[addon.instance.exports.CALC.value]) opts.push('-Dcalc');
347
353
  }
348
354
  const key = `${type} ${opts.sort().join(' ')}`;
349
355
  if (!configs.has(key)) configs.set(key, {type, options: opts});
@@ -354,8 +360,9 @@ const downloadImportLib = async () => {
354
360
  // either the default options or whatever was passed in
355
361
  if (!configs.size) {
356
362
  node = true;
357
- configs.set('node', {type: 'node', options: options || ['-Dshowdown']});
358
- configs.set('wasm', {type: 'wasm', options: options || ['-Dshowdown']});
363
+ const DEFAULT = ['-Dshowdown'];
364
+ configs.set('node', {type: 'node', options: options || DEFAULT});
365
+ configs.set('wasm', {type: 'wasm', options: options || DEFAULT});
359
366
  }
360
367
 
361
368
  const headers = node ? await downloadHeaders() : undefined;
@@ -365,8 +372,10 @@ const downloadImportLib = async () => {
365
372
  const args = ['build', '-p', 'build', ...opts];
366
373
  if (!process.env.DEBUG_PKMN_ENGINE) args.push('-Doptimize=ReleaseFast', '-Dstrip');
367
374
  if (config.type === 'node') {
368
- args.push(`-Dnode-headers=${headers}`);
369
- if (process.platform === 'win32') args.push(`-Dnode-import-library=${lib}`);
375
+ args.push(`-Dnode-headers=${path.relative(ROOT, headers)}`);
376
+ if (process.platform === 'win32') {
377
+ args.push(`-Dnode-import-library=${path.relative(ROOT, lib)}`);
378
+ }
370
379
  } else {
371
380
  args.push('-Dwasm');
372
381
  }
@@ -381,8 +390,14 @@ const downloadImportLib = async () => {
381
390
  const prefix = process.platform === 'win32' ? '' : 'lib';
382
391
  const ext = process.platform === 'darwin'
383
392
  ? 'dylib' : process.platform === 'win32' ? 'dll' : 'so';
384
- const actual = path.join('build', 'lib', `${prefix}pkmn${suffix}.node.${ext}`);
385
- fs.renameSync(path.join(ROOT, actual), path.join(ROOT, artifact));
393
+ try {
394
+ const actual = path.join(ROOT, 'build', 'lib', `${prefix}pkmn${suffix}.node.${ext}`);
395
+ fs.renameSync(actual, artifact);
396
+ } catch {
397
+ // ziglang/zig#19743 changed this path
398
+ const actual = path.join(ROOT, 'build', 'bin', `${prefix}pkmn${suffix}.node.${ext}`);
399
+ fs.renameSync(actual, artifact);
400
+ }
386
401
  }
387
402
  }
388
403
  })().catch(e => {
@@ -8,31 +8,54 @@ try {
8
8
  }
9
9
 
10
10
  const {execFileSync} = require('child_process');
11
+ const {readFileSync} = require('fs');
12
+ const {join, resolve} = require('path');
11
13
 
12
- const {Generations} = require('@pkmn/data');
14
+ const ROOT = resolve(__dirname, '..', '..');
15
+ const packageJSON = JSON.parse(readFileSync(join(ROOT, 'package.json'), 'utf8'));
13
16
 
14
- const {run} = require('../../build/tools/debug');
17
+ const missing = [];
18
+ for (const dep of ['@pkmn/img', 'html-minifier', 'esbuild']) {
19
+ try {
20
+ require.resolve(dep);
21
+ } catch (e) {
22
+ if (e.code !== 'MODULE_NOT_FOUND') throw e;
23
+ missing.push(`${dep}@${packageJSON.devDependencies[dep]}`);
24
+ }
25
+ }
15
26
 
16
- let Dex;
27
+ let Dex = undefined;
17
28
  try {
18
29
  Dex = require('@pkmn/sim').Dex;
19
30
  } catch (err) {
20
31
  if (err.code !== 'MODULE_NOT_FOUND') throw err;
21
32
  try {
22
- require.resolve('@pkmn/dex');
33
+ Dex = require('@pkmn/dex').Dex;
23
34
  } catch (e) {
24
35
  if (e.code !== 'MODULE_NOT_FOUND') throw e;
25
- execFileSync('npm', ['install', '@pkmn/dex', '--global', '--silent']);
36
+ missing.push(`@pkmn/dex@${packageJSON.dependencies['@pkmn/data']}`);
26
37
  }
38
+ }
27
39
 
40
+ if (missing.length) {
28
41
  if (+/^v(\d+)/.exec(process.version)[1] < 16) {
29
42
  console.error('pkmn-debug requires Node v16+');
30
43
  process.exit(1);
31
44
  }
32
45
 
33
- Dex = require('@pkmn/dex').Dex;
46
+ execFileSync('npm', ['install', ...missing, '--global'], {encoding: 'utf8'});
47
+
48
+ const node_modules = execFileSync('npm', ['root', '--global'], {encoding: 'utf8'}).trim();
49
+ if (!process.env.NODE_PATH || !process.env.NODE_PATH.includes(node_modules)) {
50
+ console.error(`NODE_PATH must include npm's global node_modules directory: '${node_modules}'`);
51
+ process.exit(1);
52
+ }
34
53
  }
35
54
 
55
+ const {Generations} = require('@pkmn/data');
56
+
57
+ const {run} = require('../../build/tools/debug');
58
+
36
59
  run(new Generations(Dex)).catch(err => {
37
60
  console.error(err.message);
38
61
  process.exit(1);
@@ -0,0 +1,121 @@
1
+ const js = @import("../common/js.zig");
2
+ const pkmn = @import("../pkmn.zig");
3
+ const std = @import("std");
4
+
5
+ const assert = std.debug.assert;
6
+
7
+ const c = @cImport({
8
+ @cDefine("NAPI_VERSION", "8");
9
+ @cInclude("node_api.h");
10
+ });
11
+
12
+ pub fn register(env: c.napi_env) c.napi_value {
13
+ const object = js.Object.init(env);
14
+ const properties = [_]c.napi_property_descriptor{
15
+ js.Property.init("options", .{ .value = options(env) }),
16
+ js.Property.init("bindings", .{ .value = bindings(env) }),
17
+ };
18
+ assert(c.napi_define_properties(env, object, properties.len, &properties) == c.napi_ok);
19
+ return object;
20
+ }
21
+
22
+ fn options(env: c.napi_env) c.napi_value {
23
+ const object = js.Object.init(env);
24
+ const properties = [_]c.napi_property_descriptor{
25
+ js.Property.init("showdown", .{ .value = js.Boolean.init(env, pkmn.options.showdown) }),
26
+ js.Property.init("log", .{ .value = js.Boolean.init(env, pkmn.options.log) }),
27
+ js.Property.init("chance", .{ .value = js.Boolean.init(env, pkmn.options.chance) }),
28
+ js.Property.init("calc", .{ .value = js.Boolean.init(env, pkmn.options.calc) }),
29
+ };
30
+ assert(c.napi_define_properties(env, object, properties.len, &properties) == c.napi_ok);
31
+ return object;
32
+ }
33
+
34
+ fn bindings(env: c.napi_env) c.napi_value {
35
+ const array = js.Array.init(env, .{ .length = 1 });
36
+ js.Array.set(env, array, 0, bind(env, pkmn.gen1));
37
+ return array;
38
+ }
39
+
40
+ fn bind(env: c.napi_env, gen: anytype) c.napi_value {
41
+ const choices_size: u32 = @intCast(gen.CHOICES_SIZE);
42
+ const logs_size: u32 = @intCast(gen.LOGS_SIZE);
43
+ const object = js.Object.init(env);
44
+ const properties = [_]c.napi_property_descriptor{
45
+ js.Property.init("CHOICES_SIZE", .{ .value = js.Number.init(env, choices_size) }),
46
+ js.Property.init("LOGS_SIZE", .{ .value = js.Number.init(env, logs_size) }),
47
+ js.Property.init("update", .{ .method = update(gen) }),
48
+ js.Property.init("choices", .{ .method = choices(gen) }),
49
+ };
50
+ assert(c.napi_define_properties(env, object, properties.len, &properties) == c.napi_ok);
51
+ return object;
52
+ }
53
+
54
+ fn update(gen: anytype) c.napi_callback {
55
+ return struct {
56
+ fn call(env: c.napi_env, info: c.napi_callback_info) callconv(.C) c.napi_value {
57
+ var argc: usize = 4;
58
+ var argv: [4]c.napi_value = undefined;
59
+ assert(c.napi_get_cb_info(env, info, &argc, &argv, null, null) == c.napi_ok);
60
+ assert(argc == 4);
61
+
62
+ var data: ?*anyopaque = undefined;
63
+ var len: usize = 0;
64
+ assert(c.napi_get_arraybuffer_info(env, argv[0], &data, &len) == c.napi_ok);
65
+ assert(len == @sizeOf(gen.Battle(gen.PRNG)));
66
+
67
+ var battle: *gen.Battle(gen.PRNG) = @alignCast(@ptrCast(data.?));
68
+ const c1: pkmn.Choice = @bitCast(js.Number.get(env, argv[1], u8));
69
+ const c2: pkmn.Choice = @bitCast(js.Number.get(env, argv[2], u8));
70
+
71
+ var vtype: c.napi_valuetype = undefined;
72
+ assert(c.napi_typeof(env, argv[3], &vtype) == c.napi_ok);
73
+ const result = switch (vtype) {
74
+ c.napi_undefined, c.napi_null => battle.update(c1, c2, &gen.NULL),
75
+ else => result: {
76
+ assert(c.napi_get_arraybuffer_info(env, argv[3], &data, &len) == c.napi_ok);
77
+ assert(len == gen.LOGS_SIZE);
78
+
79
+ const buf = @as([*]u8, @ptrCast(data.?))[0..gen.LOGS_SIZE];
80
+ var stream: pkmn.protocol.ByteStream = .{ .buffer = buf };
81
+ // TODO: extract out
82
+ var opts = pkmn.battle.options(
83
+ pkmn.protocol.FixedLog{ .writer = stream.writer() },
84
+ gen.chance.NULL,
85
+ gen.calc.NULL,
86
+ );
87
+ break :result battle.update(c1, c2, &opts);
88
+ },
89
+ } catch unreachable;
90
+
91
+ return js.Number.init(env, @as(u8, @bitCast(result)));
92
+ }
93
+ }.call;
94
+ }
95
+
96
+ fn choices(gen: anytype) c.napi_callback {
97
+ return struct {
98
+ fn call(env: c.napi_env, info: c.napi_callback_info) callconv(.C) c.napi_value {
99
+ var argc: usize = 4;
100
+ var argv: [4]c.napi_value = undefined;
101
+ assert(c.napi_get_cb_info(env, info, &argc, &argv, null, null) == c.napi_ok);
102
+ assert(argc == 4);
103
+
104
+ var data: ?*anyopaque = undefined;
105
+ var len: usize = 0;
106
+ assert(c.napi_get_arraybuffer_info(env, argv[0], &data, &len) == c.napi_ok);
107
+ assert(len == @sizeOf(gen.Battle(gen.PRNG)));
108
+
109
+ var battle: *gen.Battle(gen.PRNG) = @alignCast(@ptrCast(data.?));
110
+ const player: pkmn.Player = @enumFromInt(js.Number.get(env, argv[1], u8));
111
+ const request: pkmn.Choice.Type = @enumFromInt(js.Number.get(env, argv[2], u8));
112
+
113
+ assert(c.napi_get_arraybuffer_info(env, argv[3], &data, &len) == c.napi_ok);
114
+ assert(len == gen.CHOICES_SIZE);
115
+
116
+ const out = @as([*]pkmn.Choice, @ptrCast(data.?))[0..gen.CHOICES_SIZE];
117
+ const n = battle.choices(player, request, out);
118
+ return js.Number.init(env, @as(u8, @bitCast(n)));
119
+ }
120
+ }.call;
121
+ }
@@ -0,0 +1,58 @@
1
+ const pkmn = @import("../pkmn.zig");
2
+ const std = @import("std");
3
+
4
+ const assert = std.debug.assert;
5
+
6
+ const Enum = if (@hasField(std.builtin.Type, "enum")) .@"enum" else .Enum;
7
+
8
+ pub const options = pkmn.options;
9
+
10
+ pub fn gen(comptime num: comptime_int) type {
11
+ const g = @field(pkmn, "gen" ++ std.fmt.comptimePrint("{d}", .{num}));
12
+ return struct {
13
+ pub const CHOICES_SIZE = size(g.CHOICES_SIZE);
14
+ pub const LOGS_SIZE = size(g.LOGS_SIZE);
15
+
16
+ pub fn update(
17
+ battle: *g.Battle(g.PRNG),
18
+ c1: pkmn.Choice,
19
+ c2: pkmn.Choice,
20
+ options_: ?[*]u8,
21
+ ) callconv(.C) pkmn.Result {
22
+ return (if (options_) |o| result: {
23
+ const buf = @as([*]u8, @ptrCast(o))[0..g.LOGS_SIZE];
24
+ var stream: pkmn.protocol.ByteStream = .{ .buffer = buf };
25
+ // TODO: extract out
26
+ var opts = pkmn.battle.options(
27
+ pkmn.protocol.FixedLog{ .writer = stream.writer() },
28
+ g.chance.NULL,
29
+ g.calc.NULL,
30
+ );
31
+ break :result battle.update(c1, c2, &opts);
32
+ } else battle.update(c1, c2, &g.NULL)) catch unreachable;
33
+ }
34
+
35
+ pub fn choices(
36
+ battle: *g.Battle(g.PRNG),
37
+ player: u8,
38
+ request: u8,
39
+ buf: [*]u8,
40
+ ) callconv(.C) u8 {
41
+ assert(player <= @field(@typeInfo(pkmn.Player), @tagName(Enum)).fields.len);
42
+ assert(request <= @field(@typeInfo(pkmn.Choice.Type), @tagName(Enum)).fields.len);
43
+
44
+ const n = CHOICES_SIZE;
45
+ return battle.choices(@enumFromInt(player), @enumFromInt(request), @ptrCast(buf[0..n]));
46
+ }
47
+ };
48
+ }
49
+
50
+ pub fn exports() type {
51
+ @export(gen(1).update, .{ .name = "GEN1_update", .linkage = .Strong });
52
+ @export(gen(1).choices, .{ .name = "GEN1_choices", .linkage = .Strong });
53
+ return struct {};
54
+ }
55
+
56
+ fn size(n: usize) u32 {
57
+ return std.math.ceilPowerOfTwo(u32, @as(u32, @intCast(n))) catch unreachable;
58
+ }