@pkmn/engine 0.1.0-dev.437f6a52 → 0.1.0-dev.46307385

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
@@ -12,6 +12,14 @@
12
12
  <img alt="License" src="https://img.shields.io/badge/License-MIT-blue.svg" />
13
13
  </a>
14
14
  </p>
15
+
16
+ > [!WARNING]
17
+ > **This project is under heavy development** and currently the `main` branch contains numerous breaking
18
+ > changes which may not work and which are not fully documented. Please **wait for the forthcoming
19
+ > initial v0.1 release** before depending on this project (code from the
20
+ > [`old`](https://github.com/pkmn/engine/releases/tag/old) tag can also be used to experiment with a
21
+ > more stable version of the codebase).
22
+
15
23
  <hr />
16
24
 
17
25
  A minimal, complete, Pokémon battle simulation engine optimized for performance and
@@ -49,9 +57,9 @@ $ zig build --prefix /usr/local -Doptimize=ReleaseFast
49
57
  ```
50
58
 
51
59
  The Zig website has [installation instructions](https://ziglang.org/learn/getting-started/) which
52
- walk through how to install Zig on each platform - the engine code should work on Zig v0.11.0 dev
53
- build 3859 or greater, though tracks Zig's master branch so this may change in the future if
54
- breaking language changes are introduced:
60
+ walk through how to install Zig on each platform - the engine code should work on Zig v0.11.0 or
61
+ greater, though tracks Zig's master branch so this may change in the future if breaking language
62
+ changes are introduced.
55
63
 
56
64
  `libpkmn` can be built with `-Dshowdown` to instead produce the Pokémon Showdown compatible
57
65
  `libpkmn-showdown` library. Furthermore, protocol message logging can be enabled through `-Dlog`.
@@ -67,12 +75,12 @@ $ npm install @pkmn/engine
67
75
  ```
68
76
 
69
77
  The driver depends on being able to find compiled Node/WASM addons in
70
- `node_modules/@pkmn/engine/build/lib` in order to be useful. When you install the package a
71
- [`postinstall` lifecycle script](https://docs.npmjs.com/cli/v8/using-npm/scripts) will run
72
- [`install-pkmn-engine`](src/bin/install-pkmn-engine) which will check for a compatible `zig`
73
- compiler (see above regarding minimum version) and download one to
74
- `node_module/@pkmn/engine/build/bin` if it can't find one, as well as looking for (and downloading,
75
- if necessary) the required Node headers needed to successfully build the addons natively.
78
+ `node_modules/@pkmn/engine/build/lib` to be useful. When you install the package a [`postinstall`
79
+ lifecycle script](https://docs.npmjs.com/cli/v8/using-npm/scripts) runs
80
+ [`install-pkmn-engine`](src/bin/install-pkmn-engine) which checks for a compatible `zig` compiler
81
+ (see earlier regarding minimum version) and download one to `node_module/@pkmn/engine/build/bin` if
82
+ it can't find one, as well as looking for (and downloading, if necessary) the required Node headers
83
+ needed to successfully build the addons natively.
76
84
 
77
85
  **If you have configured `npm` to `--ignore-scripts` you must either run `npx install-pkmn-engine`
78
86
  directly or build the addons manually and place the artifacts in the expected paths.**
@@ -100,7 +108,7 @@ configuring whether or not Pokémon Showdown compatibility mode or protocol mess
100
108
  enabled. Alternatively, you may set options via a `pkmn_options` [root source file
101
109
  declaration](https://ziglang.org/documentation/master/#Root-Source-File). There are several
102
110
  undocumented internal options that can be tweaked as well via build or root options, though these
103
- options are not officially supported, affect correctness, and may change meaning or behavior without
111
+ options aren't officially supported, affect correctness, and may change meaning or behavior without
104
112
  warning. Use at your own risk.
105
113
 
106
114
  ```zig
@@ -112,11 +120,11 @@ pub const pkmn_options = .{ .showdown = true, .log = true };
112
120
  For each Pokémon generation, the engine provides a battle structure with two functions - a function
113
121
  to `update` the battle's state based on both players' choices and a function that defines which
114
122
  `choices` are valid at that decision point (at the beginning of a battle both player's must "pass"
115
- as their first choice in order to switch in the first member of their party). If `-Dlog` protocol
116
- logging is enabled each update will produce logs which can be decoded into a buffer (`LOGS_SIZE`
117
- constants are provided to make it easy to allocate a buffer of the correct size). Each `update` will
118
- return a result to indicate either that the battle has terminated or which types of choices will be
119
- available for each player.
123
+ as their first choice to switch in the first member of their party). If `-Dlog` protocol logging is
124
+ enabled each update produces logs which can be decoded into a buffer (`LOGS_SIZE` constants are
125
+ provided to make it easy to allocate a buffer of the correct size). Each `update` returns a result
126
+ to indicate either that the battle has terminated or which types of choices are available for each
127
+ player.
120
128
 
121
129
  Unlike [Pokémon Showdown's
122
130
  SIM-PROTOCOL](https://github.com/smogon/pokemon-showdown/blob/master/sim/SIM-PROTOCOL.md#choice-requests)
@@ -128,7 +136,7 @@ state or cause the engine to crash.**
128
136
 
129
137
  Battles may be played out from any point but to freshly initialize a battle which is yet to start
130
138
  the turn count and active Pokémon should be zeroed out (driver code should handle this for you).
131
- Most driver code should also provide helpers to make initialize a battle convenient - check the
139
+ Most driver code should also provide helpers to make initializing battle convenient - check the
132
140
  respective documentation and examples for the bindings being used. The engine's [protocol
133
141
  documentation](docs/PROTOCOL.md) goes into greater detail on the specifics of updates and the
134
142
  potential logs that may result.
@@ -140,7 +148,7 @@ potential logs that may result.
140
148
 
141
149
  [`pkmn.h`](src/include/pkmn.h) exports the C API for `libpkmn`. Symbols are all prefixed with
142
150
  `pkmn_` to avoid name collisions. If `-Dlog` is enabled and logging throws an error then the error
143
- will be encoded in the `pkmn_result` and can be checked with `pkmn_error`.
151
+ is encoded in the `pkmn_result` and can be checked with `pkmn_error`.
144
152
 
145
153
  ```c
146
154
  #include <pkmn.h>
@@ -161,17 +169,17 @@ if (pkmn_error(result)) exit(1);
161
169
 
162
170
  [(full code)](src/examples/c/example.c)
163
171
 
164
- The C API does not export any helpers for creating or accessing the opaque battle objects - it is
172
+ The C API doesn't export any helpers for creating or accessing the opaque battle objects - it's
165
173
  instead intended to be used as the foundation for more ergonomic bindings in [other
166
174
  languages](#other) (the lack of namespaces and bit fields having an implementation-defined layout in
167
175
  C are the main contributing factors to the sparseness of what `libpkmn` chooses to expose).
168
176
 
169
177
  ### JavaScript / TypeScript
170
178
 
171
- `@pkmn/engine` depends on the [`@pkmn/data`](https://www.npmjs.com/package/@pkmn/data) which
179
+ `@pkmn/engine` depends on the [`@pkmn/data`](https://www.npmjs.com/package/@pkmn/data) package which
172
180
  requires a `Dex` implementation to be provided as well. The `Battle.create` function can be used to
173
181
  initialize a `Battle` from the beginning, or `Battle.restore` can be used to re-instantiate a battle
174
- which is in already progress. If logging is enabled the output can be turned into Pokémon Showdown
182
+ which is already in progress. If logging is enabled the output can be turned into Pokémon Showdown
175
183
  protocol via `Log.parse`.
176
184
 
177
185
  ```ts
@@ -196,18 +204,18 @@ console.log(result);
196
204
 
197
205
  [(full code)](src/examples/js/example.ts)
198
206
 
199
- By default, the `@pkmn/engine` package will compile the engine with `-Dshowdown`, though by running
207
+ By default, the `@pkmn/engine` package compiles the engine with `-Dshowdown`, though by running
200
208
  `install-pkmn-engine` directly and passing in `--options` you can override this default and build
201
209
  different configurations of the extension for the driver to use. The driver can support
202
210
  configurations both with and without Pokémon Showdown compatibility simultaneously if present. On
203
- update, the post-install script will attempt to rebuild whichever extensions it finds with the same
211
+ update, the post-install script attempts to rebuild whichever extensions it finds with the same
204
212
  configuration parameters that were originally used meaning updating to the newest version of the
205
213
  library should be seamless.
206
214
 
207
215
  Despite relying on the native engine code, the `@pkmn/engine` code is designed to also work in
208
216
  browsers which support [WebAssembly](https://webassembly.org/). Running `npm run start:web` from the
209
- [`examples`](src/examples/js) directory will start a server that can be used to demonstrate the
210
- engine running in the browser.
217
+ [`examples`](src/examples/js) directory starts a server that can be used to demonstrate the engine
218
+ running in the browser.
211
219
 
212
220
  ### Zig
213
221
 
@@ -240,7 +248,7 @@ std.debug.print("{}\n", .{result.type});
240
248
 
241
249
  The Zig package also supports some APIs which are difficult to expose elsewhere such as the
242
250
  `FixedRNG` which allows you to fully specify the exact RNG frames (which can be useful for ensuring
243
- certain outcomes/effects always occur) for a battle, though doing so will change the size of the
251
+ certain outcomes/effects always occur) for a battle, though doing so changes the size of the
244
252
  `Battle` object.
245
253
 
246
254
  ### Other
@@ -251,7 +259,7 @@ simplify the process even further [`src/data`](src/data) contains JSON dumps of
251
259
  data, structure sizes and offsets, and protocol information used by the reference driver code. The
252
260
  following is a list of known `libpkmn` bindings written by developers outside of the [pkmn
253
261
  organization](https://github.com/pkmn) that may be helpful (though note that these projects may not
254
- necessarily be up-to-date/complete/correct - inclusion in this list does not imply endorsement):
262
+ necessarily be up-to-date/complete/correct - inclusion in this list doesn't imply endorsement):
255
263
 
256
264
  | Language | License | URL |
257
265
  | ---------- | --------- | ------------------------------------ |
@@ -279,7 +287,7 @@ By default, `pkmn-debug` expects to read [binary debug protocol](docs/PROTOCOL.m
279
287
  $ <cmd> | pkmn-debug > index.html
280
288
  ```
281
289
 
282
- Alternatively, if a single filename argument is passed to the `pkmn-debug` it will read from that
290
+ Alternatively, if a single filename argument is passed to the `pkmn-debug` it reads from that
283
291
  instead:
284
292
 
285
293
  ```sh
@@ -301,14 +309,14 @@ Currently, most of the foundational work from stage 0 is done:
301
309
 
302
310
  - [benchmark and integration testing](src/test) infrastructure
303
311
  - [documentation](docs) about design, research, methodology, etc
304
- - definition and implementation of the [protocol](docs/PROTOCOL.md) that will be used by the engine
312
+ - definition and implementation of the [protocol](docs/PROTOCOL.md) that's used by the engine
305
313
 
306
- **Stage 1 is currently in progress** and will see the implementation of the actual Generation I & II
314
+ **Stage 1 is currently in progress** and involves the implementation of the actual Generation I & II
307
315
  battle engines, followed by Generation III & IV in stage 2. The implementation of further Pokémon
308
- generations is in scope for the project but should not be considered as part of the immediate
309
- roadmap (i.e. exploring the options for broadening support for old generation APIs will be given
310
- higher priority than implementing more modern generations). Furthermore, implementation of modern
311
- generations is soft-blocked on the [availability of high quality
316
+ generations is in scope for the project but shouldn't be considered part of the immediate roadmap
317
+ (i.e. exploring the options for broadening support for old generation APIs is given higher priority
318
+ than implementing more modern generations). Furthermore, implementation of modern generations is
319
+ soft-blocked on the [availability of high quality
312
320
  decompilations](https://github.com/orgs/pret/repositories) of the original games in question.
313
321
 
314
322
  Certain features will always be deemed **out of scope**:
@@ -326,10 +334,10 @@ The pkmn engine is distributed under the terms of the [MIT License](LICENSE).
326
334
  [^1]: In the case of Pokémon Showdown, only bugs which stem from a misimplementation of specific
327
335
  effects are reproduced in the engine, bugs which are the result of a misunderstanding of the
328
336
  fundamental mechanics of Pokémon or which simply arise due to specific Pokémon Showdown
329
- implementation details that are not replicable without making the same (incorrect) architectural
330
- choices are not. Furthermore, the "Pokémon Showdown" code referenced by this project includes
337
+ implementation details that aren't replicable without making the same (incorrect) architectural
338
+ choices aren't. Furthermore, the "Pokémon Showdown" code referenced by this project includes
331
339
  several [patches](docs/TESTING.md#patches) to improve accuracy and smooth over some of the more
332
340
  egregious implementation issues. In practical terms, the vast majority of games played out in the
333
- pkmn engine's compatibility mode and on this patched Pokémon Showdown simulator will be the same,
334
- it is only in a well defined and documented set of circumstances where the two implementations
341
+ pkmn engine's compatibility mode and on this patched Pokémon Showdown simulator are the same,
342
+ it's only in a well defined and documented set of circumstances where the two implementations
335
343
  diverge.
package/build.zig CHANGED
@@ -35,6 +35,7 @@ pub fn build(b: *std.Build) !void {
35
35
  const strip = b.option(bool, "strip", "Strip debugging symbols from binary") orelse false;
36
36
  const pic = b.option(bool, "pic", "Force position independent code") orelse false;
37
37
  const emit_asm = b.option(bool, "emit-asm", "Output .s (assembly code)") orelse false;
38
+ const emit_ll = b.option(bool, "emit-ll", "Output .ll (LLVM IR)") orelse false;
38
39
 
39
40
  const cmd = b.findProgram(&.{"strip"}, &.{}) catch null;
40
41
 
@@ -65,16 +66,16 @@ pub fn build(b: *std.Build) !void {
65
66
  const addon = b.fmt("{s}.node", .{name});
66
67
  const lib = b.addSharedLibrary(.{
67
68
  .name = addon,
69
+ .main_pkg_path = .{ .path = "." },
68
70
  .root_source_file = .{ .path = "src/lib/binding/node.zig" },
69
71
  .optimize = optimize,
70
72
  .target = target,
71
73
  });
72
74
  lib.addOptions("build_options", options);
73
- lib.setMainPkgPath("./");
74
- lib.addSystemIncludePath(headers);
75
+ lib.addSystemIncludePath(.{ .path = headers });
75
76
  lib.linkLibC();
76
77
  if (node_import_lib) |il| {
77
- lib.addObjectFile(il);
78
+ lib.addObjectFile(.{ .path = il });
78
79
  } else if ((try std.zig.system.NativeTargetInfo.detect(target)).target.os.tag == .windows) {
79
80
  try std.io.getStdErr().writeAll("Must provide --node-import-library path on Windows\n");
80
81
  std.process.exit(1);
@@ -94,6 +95,7 @@ pub fn build(b: *std.Build) !void {
94
95
  } else if (wasm) {
95
96
  const lib = b.addSharedLibrary(.{
96
97
  .name = name,
98
+ .main_pkg_path = .{ .path = "." },
97
99
  .root_source_file = .{ .path = "src/lib/binding/wasm.zig" },
98
100
  .optimize = switch (optimize) {
99
101
  .ReleaseFast, .ReleaseSafe => .ReleaseSmall,
@@ -102,7 +104,6 @@ pub fn build(b: *std.Build) !void {
102
104
  .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
103
105
  });
104
106
  lib.addOptions("build_options", options);
105
- lib.setMainPkgPath("./");
106
107
  lib.stack_size = wasm_stack_size;
107
108
  lib.rdynamic = true;
108
109
  lib.strip = strip;
@@ -120,14 +121,14 @@ pub fn build(b: *std.Build) !void {
120
121
  } else if (dynamic) {
121
122
  const lib = b.addSharedLibrary(.{
122
123
  .name = name,
124
+ .main_pkg_path = .{ .path = "." },
123
125
  .root_source_file = .{ .path = "src/lib/binding/c.zig" },
124
126
  .version = try std.SemanticVersion.parse(version),
125
127
  .optimize = optimize,
126
128
  .target = target,
127
129
  });
128
130
  lib.addOptions("build_options", options);
129
- lib.setMainPkgPath("./");
130
- lib.addIncludePath("src/include");
131
+ lib.addIncludePath(.{ .path = "src/include" });
131
132
  maybeStrip(b, lib, b.getInstallStep(), strip, cmd);
132
133
  if (pic) lib.force_pic = pic;
133
134
  b.installArtifact(lib);
@@ -135,17 +136,30 @@ pub fn build(b: *std.Build) !void {
135
136
  } else {
136
137
  const lib = b.addStaticLibrary(.{
137
138
  .name = name,
139
+ .main_pkg_path = .{ .path = "." },
138
140
  .root_source_file = .{ .path = "src/lib/binding/c.zig" },
139
141
  .optimize = optimize,
140
142
  .target = target,
141
143
  });
142
144
  lib.addOptions("build_options", options);
143
- lib.setMainPkgPath("./");
144
- lib.addIncludePath("src/include");
145
+ lib.addIncludePath(.{ .path = "src/include" });
145
146
  lib.bundle_compiler_rt = true;
146
147
  maybeStrip(b, lib, b.getInstallStep(), strip, cmd);
147
148
  if (pic) lib.force_pic = pic;
148
- if (emit_asm) lib.emit_asm = .emit;
149
+ if (emit_asm) {
150
+ b.getInstallStep().dependOn(&b.addInstallFileWithDir(
151
+ lib.getEmittedAsm(),
152
+ .prefix,
153
+ b.fmt("{s}.s", .{name}),
154
+ ).step);
155
+ }
156
+ if (emit_ll) {
157
+ b.getInstallStep().dependOn(&b.addInstallFileWithDir(
158
+ lib.getEmittedLlvmIr(),
159
+ .prefix,
160
+ b.fmt("{s}.ll", .{name}),
161
+ ).step);
162
+ }
149
163
  b.installArtifact(lib);
150
164
  c = true;
151
165
  }
@@ -217,19 +231,15 @@ pub fn build(b: *std.Build) !void {
217
231
  fuzz_config.tool.name = "fuzz";
218
232
  const fuzz = tool(b, "src/test/fuzz.zig", fuzz_config);
219
233
 
234
+ const analyze = tool(b, "src/tools/analyze.zig", tools);
220
235
  const dump = tool(b, "src/tools/dump.zig", tools);
221
236
  const serde = tool(b, "src/tools/serde.zig", tools);
222
237
  const transitions = tool(b, "src/tools/transitions.zig", tools);
223
238
 
224
- const lint_exe =
225
- b.addExecutable(.{ .name = "lint", .root_source_file = .{ .path = "src/tools/lint.zig" } });
226
- if (tests.build) tests.step.dependOn(&lint_exe.step);
227
- const lint = b.addRunArtifact(lint_exe);
228
-
239
+ b.step("analyze", "Run LLVM analysis tool").dependOn(&analyze.step);
229
240
  b.step("benchmark", "Run benchmark code").dependOn(&benchmark.step);
230
241
  b.step("dump", "Run protocol dump tool").dependOn(&dump.step);
231
242
  b.step("fuzz", "Run fuzz tester").dependOn(&fuzz.step);
232
- b.step("lint", "Lint source files").dependOn(&lint.step);
233
243
  b.step("serde", "Run serialization/deserialization tool").dependOn(&serde.step);
234
244
  b.step("test", "Run all tests").dependOn(&tests.step);
235
245
  b.step("tools", "Install tools").dependOn(&ToolsStep.create(b, &exes).step);
@@ -263,12 +273,6 @@ const Config = struct {
263
273
  cmd: ?[]const u8,
264
274
  };
265
275
 
266
- const TESTS = .{
267
- "src/lib/common/test.zig",
268
- "src/lib/gen1/test.zig",
269
- "src/lib/gen2/test.zig",
270
- };
271
-
272
276
  const TestStep = struct {
273
277
  step: std.Build.Step,
274
278
  build: bool,
@@ -283,26 +287,27 @@ const TestStep = struct {
283
287
  const step = std.Build.Step.init(.{ .id = .custom, .name = "Run all tests", .owner = b });
284
288
  self.* = TestStep{ .step = step, .build = test_filter == null };
285
289
 
286
- const paths: []const []const u8 =
287
- if (test_file) |t| &.{t} else if (coverage != null) &.{"src/lib/test.zig"} else &TESTS;
288
- for (paths) |path| {
289
- const tests = b.addTest(.{
290
- .name = std.fs.path.basename(std.fs.path.dirname(path).?),
291
- .root_source_file = .{ .path = path },
292
- .optimize = config.optimize,
293
- .target = config.target,
294
- .filter = test_filter,
295
- });
296
- tests.setMainPkgPath("./");
297
- tests.addOptions("build_options", options);
298
- tests.single_threaded = true;
299
- maybeStrip(b, tests, &tests.step, config.strip, config.cmd);
300
- if (config.pic) tests.force_pic = config.pic;
301
- if (coverage) |c| {
302
- tests.setExecCmd(&.{ "kcov", "--include-pattern=src/lib", c, null });
303
- }
304
- self.step.dependOn(&b.addRunArtifact(tests).step);
290
+ const path = test_file orelse "src/lib/test.zig";
291
+ const tests = b.addTest(.{
292
+ .name = b.fmt("{s}-{s}", .{
293
+ std.fs.path.basename(std.fs.path.dirname(path).?),
294
+ std.fs.path.stem(std.fs.path.basename(path)),
295
+ }),
296
+ .main_pkg_path = .{ .path = "." },
297
+ .root_source_file = .{ .path = path },
298
+ .optimize = config.optimize,
299
+ .target = config.target,
300
+ .filter = test_filter,
301
+ });
302
+ tests.addOptions("build_options", options);
303
+ tests.single_threaded = true;
304
+ maybeStrip(b, tests, &tests.step, config.strip, config.cmd);
305
+ if (config.pic) tests.force_pic = config.pic;
306
+ if (coverage) |c| {
307
+ tests.setExecCmd(&.{ "kcov", "--include-pattern=src/lib", c, null });
305
308
  }
309
+ self.step.dependOn(&b.addRunArtifact(tests).step);
310
+
306
311
  return self;
307
312
  }
308
313
  };
@@ -350,7 +355,7 @@ const ToolsStep = struct {
350
355
  const self = b.allocator.create(ToolsStep) catch @panic("OOM");
351
356
  const step = std.Build.Step.init(.{ .id = .custom, .name = "Install tools", .owner = b });
352
357
  self.* = ToolsStep{ .step = step };
353
- for (exes.items) |t| self.step.dependOn(&b.addInstallArtifact(t).step);
358
+ for (exes.items) |t| self.step.dependOn(&b.addInstallArtifact(t, .{}).step);
354
359
  return self;
355
360
  }
356
361
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pkmn/engine",
3
- "version": "0.1.0-dev.437f6a52",
3
+ "version": "0.1.0-dev.46307385",
4
4
  "description": "A minimal, complete, Pokémon battle simulation engine optimized for performance",
5
5
  "repository": "github:pkmn/engine",
6
6
  "license": "MIT",
@@ -34,11 +34,18 @@
34
34
  "src/bin/install-pkmn-engine",
35
35
  "src/lib/binding/node.zig",
36
36
  "src/lib/binding/wasm.zig",
37
+ "src/lib/common/battle.zig",
37
38
  "src/lib/common/data.zig",
38
39
  "src/lib/common/debug.zig",
40
+ "src/lib/common/js.zig",
41
+ "src/lib/common/optional.zig",
39
42
  "src/lib/common/options.zig",
40
43
  "src/lib/common/protocol.zig",
44
+ "src/lib/common/rational.zig",
41
45
  "src/lib/common/rng.zig",
46
+ "src/lib/common/util.zig",
47
+ "src/lib/gen1/calc.zig",
48
+ "src/lib/gen1/chance.zig",
42
49
  "src/lib/gen1/data.zig",
43
50
  "src/lib/gen1/data/moves.zig",
44
51
  "src/lib/gen1/data/species.zig",
@@ -66,30 +73,30 @@
66
73
  "access": "public"
67
74
  },
68
75
  "dependencies": {
69
- "@pkmn/data": "^0.7.44",
76
+ "@pkmn/data": "^0.7.46",
70
77
  "@pkmn/protocol": "^0.6.12"
71
78
  },
72
79
  "devDependencies": {
73
- "@pkmn/eslint-config": "^3.2.0",
74
- "@pkmn/img": "^0.2.12",
80
+ "@pkmn/eslint-config": "^5.0.0",
81
+ "@pkmn/img": "^0.2.13",
75
82
  "@pkmn/sets": "^5.0.4",
76
- "@pkmn/sim": "0.7.44",
83
+ "@pkmn/sim": "0.7.46",
77
84
  "@types/html-minifier": "^4.0.2",
78
- "@types/jest": "^29.5.2",
85
+ "@types/jest": "^29.5.3",
79
86
  "@types/minimist": "^1.2.2",
80
87
  "@types/mustache": "^4.2.2",
81
- "@types/node": "^20.3.1",
82
- "@vitest/coverage-c8": "^0.32.2",
83
- "binaryen": "^113.0.0",
84
- "eslint": "^8.43.0",
88
+ "@types/node": "^20.4.2",
89
+ "@vitest/coverage-c8": "^0.33.0",
90
+ "binaryen": "^114.0.0",
91
+ "eslint": "^8.44.0",
85
92
  "html-minifier": "^4.0.0",
86
93
  "json-stringify-pretty-compact": "3.0.0",
87
94
  "minimist": "^1.2.8",
88
95
  "mustache": "^4.2.0",
89
96
  "source-map-support": "^0.5.21",
90
97
  "trakr": "^0.2.0",
91
- "typescript": "^5.1.3",
92
- "vitest": "^0.32.2"
98
+ "typescript": "^5.1.6",
99
+ "vitest": "^0.33.0"
93
100
  },
94
101
  "scripts": {
95
102
  "lint": "eslint --cache src --ext ts,js && eslint src/bin/*",
@@ -140,7 +147,8 @@
140
147
  "rules": {
141
148
  "no-control-regex": "off",
142
149
  "@typescript-eslint/no-empty-interface": "off",
143
- "@typescript-eslint/no-shadow": "off"
150
+ "@typescript-eslint/no-shadow": "off",
151
+ "@typescript-eslint/no-unsafe-declaration-merging": "off"
144
152
  }
145
153
  },
146
154
  {
@@ -156,7 +164,8 @@
156
164
  "src/test/benchmark*.ts"
157
165
  ],
158
166
  "rules": {
159
- "@typescript-eslint/no-unused-vars": "off"
167
+ "@typescript-eslint/no-unused-vars": "off",
168
+ "@typescript-eslint/no-redundant-type-constituents": "off"
160
169
  }
161
170
  },
162
171
  {
@@ -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: 3859};
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';
@@ -358,7 +358,7 @@ const downloadImportLib = async () => {
358
358
  // either the default options or whatever was passed in
359
359
  if (!configs.size) {
360
360
  node = true;
361
- const DEFAULT = ['-Dshowdown', '-Dlog', '-Dchance', '-Dcalc'];
361
+ const DEFAULT = ['-Dshowdown'];
362
362
  configs.set('node', {type: 'node', options: options || DEFAULT});
363
363
  configs.set('wasm', {type: 'wasm', options: options || DEFAULT});
364
364
  }
@@ -0,0 +1,17 @@
1
+ /// Stores state required by optional features to the engine that can be passed to a generation's
2
+ /// `Battle.update` function. All generations generically support protocol logging (enabled via
3
+ /// `-Dlog`), chance actions and probability tracking (enabled via `-Dchance`), and damage
4
+ /// computation and chance overrides (`-Dcalc`), though the concrete types for these features are
5
+ /// generation dependent.
6
+ pub fn Options(comptime Log: type, comptime Chance: type, comptime Calc: type) type {
7
+ return struct { log: Log, chance: Chance, calc: Calc };
8
+ }
9
+
10
+ /// Helper to create a battle `Options` object with the provided `log`, `chance`, and `calc`.
11
+ pub fn options(
12
+ log: anytype,
13
+ chance: anytype,
14
+ calc: anytype,
15
+ ) Options(@TypeOf(log), @TypeOf(chance), @TypeOf(calc)) {
16
+ return .{ .log = log, .chance = chance, .calc = calc };
17
+ }
@@ -0,0 +1,118 @@
1
+ const std = @import("std");
2
+
3
+ const assert = std.debug.assert;
4
+
5
+ const c = @cImport({
6
+ @cDefine("NAPI_VERSION", "8");
7
+ @cInclude("node_api.h");
8
+ });
9
+
10
+ pub const Array = struct {
11
+ pub fn init(env: c.napi_env, o: struct { length: ?usize }) c.napi_value {
12
+ var result: c.napi_value = undefined;
13
+ assert(c.napi_ok == if (o.length) |n|
14
+ c.napi_create_array_with_length(env, n, &result)
15
+ else
16
+ c.napi_create_array(env, &result));
17
+ return result;
18
+ }
19
+
20
+ pub fn set(env: c.napi_env, array: c.napi_value, index: u32, value: c.napi_value) void {
21
+ assert(c.napi_set_element(env, array, index, value) == c.napi_ok);
22
+ }
23
+ };
24
+
25
+ pub const Boolean = struct {
26
+ pub fn init(env: c.napi_env, value: bool) c.napi_value {
27
+ var result: c.napi_value = undefined;
28
+ assert(c.napi_get_boolean(env, value, &result) == c.napi_ok);
29
+ return result;
30
+ }
31
+ };
32
+
33
+ pub const Number = struct {
34
+ pub fn init(env: c.napi_env, value: anytype) c.napi_value {
35
+ const T = @TypeOf(value);
36
+ var result: c.napi_value = undefined;
37
+ assert(c.napi_ok == switch (@typeInfo(T)) {
38
+ .Int => |info| switch (info.bits) {
39
+ 0...32 => switch (info.signedness) {
40
+ .signed => c.napi_create_int32(env, @as(i32, value), &result),
41
+ .unsigned => c.napi_create_uint32(env, @as(u32, value), &result),
42
+ },
43
+ 33...52 => c.napi_create_int64(env, @as(i64, value), &result),
44
+ else => @compileError("int can't be represented as JS number"),
45
+ },
46
+ else => @compileError("expected number, got: " ++ @typeName(T)),
47
+ });
48
+ return result;
49
+ }
50
+
51
+ pub fn get(env: c.napi_env, value: c.napi_value, comptime T: type) T {
52
+ switch (@typeInfo(T)) {
53
+ .Int => |info| switch (info.bits) {
54
+ 0...32 => switch (info.signedness) {
55
+ .signed => {
56
+ var result: i32 = undefined;
57
+ assert(c.napi_get_value_int32(env, value, &result) == c.napi_ok);
58
+ return if (info.bits == 32) result else @intCast(result);
59
+ },
60
+ .unsigned => {
61
+ var result: u32 = undefined;
62
+ assert(c.napi_get_value_uint32(env, value, &result) == c.napi_ok);
63
+ return if (info.bits == 32) result else @intCast(result);
64
+ },
65
+ },
66
+ 33...63 => {
67
+ var result: i64 = undefined;
68
+ assert(c.napi_get_value_int64(env, value, &result) == c.napi_ok);
69
+ return @intCast(result);
70
+ },
71
+ else => {
72
+ var result: i64 = undefined;
73
+ assert(c.napi_get_value_int64(env, value, &result) == c.napi_ok);
74
+ return switch (info.signedness) {
75
+ .signed => value,
76
+ .unsigned => if (0 <= value) @intCast(value) else unreachable,
77
+ };
78
+ },
79
+ },
80
+ else => @compileError("expected number, got: " ++ @typeName(T)),
81
+ }
82
+ }
83
+ };
84
+
85
+ pub const Object = struct {
86
+ pub fn init(env: c.napi_env) c.napi_value {
87
+ var result: c.napi_value = undefined;
88
+ assert(c.napi_create_object(env, &result) == c.napi_ok);
89
+ return result;
90
+ }
91
+ };
92
+
93
+ pub const Property = union(enum) {
94
+ method: c.napi_callback,
95
+ value: c.napi_value,
96
+
97
+ pub fn init(comptime name: [:0]const u8, property: Property) c.napi_property_descriptor {
98
+ return .{
99
+ .utf8name = name,
100
+ .name = null,
101
+ .method = switch (property) {
102
+ .method => |m| m,
103
+ .value => null,
104
+ },
105
+ .getter = null,
106
+ .setter = null,
107
+ .value = switch (property) {
108
+ .method => null,
109
+ .value => |v| v,
110
+ },
111
+ .attributes = switch (property) {
112
+ .method => c.napi_default,
113
+ .value => c.napi_enumerable,
114
+ },
115
+ .data = null,
116
+ };
117
+ }
118
+ };