@pkmn/engine 0.1.0-dev.6ebbd3bc → 0.1.0-dev.724afcb1

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 (58) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +18 -11
  3. package/build/pkg/addon/browser.js +4 -1
  4. package/build/pkg/addon/browser.js.map +1 -1
  5. package/build/pkg/addon/node.js +20 -7
  6. package/build/pkg/addon/node.js.map +1 -1
  7. package/build/pkg/addon/wasm.js.map +1 -1
  8. package/build/pkg/addon.d.ts +5 -5
  9. package/build/pkg/addon.js.map +1 -1
  10. package/build/pkg/data.js.map +1 -1
  11. package/build/pkg/gen1.d.ts +2 -1
  12. package/build/pkg/gen1.js +22 -9
  13. package/build/pkg/gen1.js.map +1 -1
  14. package/build/pkg/index.d.ts +2 -0
  15. package/build/pkg/index.js +17 -7
  16. package/build/pkg/index.js.map +1 -1
  17. package/build/pkg/protocol.d.ts +11 -2
  18. package/build/pkg/protocol.js.map +1 -1
  19. package/build/tools/debug.js +54 -10
  20. package/build/tools/debug.js.map +1 -1
  21. package/build/tools/display/debug.jsx +19 -94
  22. package/build/tools/display/debug.jsx.map +1 -1
  23. package/build/tools/display/index.js +17 -7
  24. package/build/tools/display/index.js.map +1 -1
  25. package/build/tools/display/ui.jsx +20 -9
  26. package/build/tools/display/ui.jsx.map +1 -1
  27. package/build/tools/display/util.js +140 -1
  28. package/build/tools/display/util.js.map +1 -1
  29. package/build.zig +169 -218
  30. package/package.json +26 -24
  31. package/src/bin/install-pkmn-engine +23 -7
  32. package/src/lib/bindings/c.zig +27 -81
  33. package/src/lib/bindings/node.zig +7 -11
  34. package/src/lib/bindings/wasm.zig +6 -15
  35. package/src/lib/common/array.zig +5 -12
  36. package/src/lib/common/debug.zig +33 -59
  37. package/src/lib/common/js.zig +3 -9
  38. package/src/lib/common/optional.zig +11 -21
  39. package/src/lib/common/protocol.zig +224 -189
  40. package/src/lib/common/rational.zig +275 -284
  41. package/src/lib/common/util.zig +14 -31
  42. package/src/lib/gen1/calc.zig +139 -117
  43. package/src/lib/gen1/chance.zig +112 -75
  44. package/src/lib/gen1/data/types.zig +2 -2
  45. package/src/lib/gen1/data.zig +5 -5
  46. package/src/lib/gen1/helpers.zig +8 -10
  47. package/src/lib/gen1/mechanics.zig +43 -41
  48. package/src/lib/gen2/calc.zig +3 -6
  49. package/src/lib/gen2/chance.zig +12 -18
  50. package/src/lib/gen2/data/types.zig +6 -3
  51. package/src/lib/gen2/data.zig +8 -7
  52. package/src/lib/gen2/helpers.zig +4 -6
  53. package/src/lib/gen2/mechanics.zig +18 -18
  54. package/src/lib/napi.h +2 -0
  55. package/src/lib/node.zig +1 -5
  56. package/src/lib/pkmn.zig +91 -17
  57. package/src/lib/wasm.zig +2 -6
  58. package/src/tools/display/dom.ts +43 -31
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pkmn/engine",
3
- "version": "0.1.0-dev.6ebbd3bc",
3
+ "version": "0.1.0-dev.724afcb1",
4
4
  "description": "A minimal, complete, Pokémon battle simulation engine optimized for performance",
5
5
  "repository": "github:pkmn/engine",
6
6
  "license": "MIT",
@@ -81,6 +81,7 @@
81
81
  "src/lib/gen2/generated.zig",
82
82
  "src/lib/gen2/helpers.zig",
83
83
  "src/lib/gen2/mechanics.zig",
84
+ "src/lib/napi.h",
84
85
  "src/lib/node.zig",
85
86
  "src/lib/pkmn.zig",
86
87
  "src/lib/wasm.zig",
@@ -98,38 +99,39 @@
98
99
  "access": "public"
99
100
  },
100
101
  "dependencies": {
101
- "@pkmn/data": "^0.9.22",
102
- "@pkmn/protocol": "^0.6.28"
102
+ "@pkmn/data": "0.9.35",
103
+ "@pkmn/protocol": "^0.7.2"
103
104
  },
104
105
  "devDependencies": {
105
- "@pkmn/eslint-config": "^9.1.0",
106
- "@pkmn/img": "^0.2.33",
107
- "@pkmn/sets": "^5.1.2",
108
- "@pkmn/sim": "0.9.22",
109
- "@pkmn/smogon": "^0.5.15",
110
- "@types/html-minifier": "^4.0.5",
111
- "@types/jest": "^29.5.14",
106
+ "@pkmn/dex-types": "0.9.35",
107
+ "@pkmn/eslint-config": "^9.27.0",
108
+ "@pkmn/img": "^0.3.3",
109
+ "@pkmn/sets": "^5.2.0",
110
+ "@pkmn/sim": "0.9.31",
111
+ "@pkmn/smogon": "0.5.21",
112
+ "@types/html-minifier": "^4.0.6",
113
+ "@types/jest": "^30.0.0",
112
114
  "@types/minimist": "^1.2.5",
113
- "@types/mustache": "^4.2.5",
114
- "@types/node": "^22.8.7",
115
- "@types/react": "^18.3.12",
116
- "@types/semver": "^7.5.8",
117
- "@types/vscode": "^1.95.0",
118
- "@vitest/coverage-v8": "^2.1.4",
119
- "@vscode/vsce": "^3.2.1",
120
- "binaryen": "^120.0.0",
121
- "esbuild": "^0.24.0",
122
- "eslint": "^9.14.0",
115
+ "@types/mustache": "^4.2.6",
116
+ "@types/node": "^25.6.0",
117
+ "@types/react": "^19.2.14",
118
+ "@types/semver": "^7.7.1",
119
+ "@types/vscode": "^1.118.0",
120
+ "@vitest/coverage-v8": "^4.1.5",
121
+ "@vscode/vsce": "^3.9.1",
122
+ "binaryen": "^129.0.0",
123
+ "esbuild": "^0.28.0",
124
+ "eslint": "<10",
123
125
  "html-minifier": "^4.0.0",
124
126
  "json-stringify-pretty-compact": "3.0.0",
125
127
  "minimist": "^1.2.8",
126
128
  "mustache": "^4.2.0",
127
- "semver": "^7.6.3",
129
+ "semver": "^7.7.4",
128
130
  "source-map-support": "^0.5.21",
129
- "table": "^6.8.2",
131
+ "table": "^6.9.0",
130
132
  "trakr": "^0.2.0",
131
- "typescript": "^5.6.3",
132
- "vitest": "^2.1.4"
133
+ "typescript": "^6.0.3",
134
+ "vitest": "^4.1.5"
133
135
  },
134
136
  "scripts": {
135
137
  "lint": "eslint --cache src",
@@ -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};
13
+ const ZIG_VERSION = {major: 0, minor: 16, 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';
@@ -111,15 +111,31 @@ const unpack = async (input, output) => {
111
111
  }
112
112
  };
113
113
 
114
+ const parse = s => {
115
+ try {
116
+ return JSON.parse(s);
117
+ } catch (e) {
118
+ if (!(e instanceof SyntaxError)) throw e;
119
+ const json = s
120
+ // "key": -> "key": (ensures keys are quoted)
121
+ .replace(/\.([a-zA-Z_][a-zA-Z0-9_]*)\s*=/g, '"$1":')
122
+ // .{ -> { (converts ZON struct to JSON object)
123
+ .replace(/\.\{/g, '{')
124
+ // Remove trailing commas, which are invalid in JSON
125
+ .replace(/,\s*([}\]])/g, '$1');
126
+ return JSON.parse(json);
127
+ }
128
+ };
129
+
114
130
  const find = zig => {
115
131
  try {
116
- const {zig_exe, version} = JSON.parse(sh(zig, ['env']));
132
+ const {zig_exe, version} = parse(sh(zig, ['env']));
117
133
  const [major, minor, patch, dev] = version.split('.').map(n => parseInt(n));
118
134
 
119
135
  const compatible = major > ZIG_VERSION.major ||
120
136
  (major >= ZIG_VERSION.major && minor > ZIG_VERSION.minor) ||
121
137
  (major >= ZIG_VERSION.major && minor >= ZIG_VERSION.minor && patch >= ZIG_VERSION.patch &&
122
- (!ZIG_VERSION.dev || (dev && dev >= ZIG_VERSION.dev)));
138
+ (!ZIG_VERSION.dev || (dev && dev >= parseInt(ZIG_VERSION.dev))));
123
139
 
124
140
  if (compatible) {
125
141
  log('Found existing compatible Zig executable:', zig_exe);
@@ -163,10 +179,9 @@ const install = async () => {
163
179
  }
164
180
 
165
181
  const index = JSON.parse(await fetch(INDEX));
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}`];
182
+ const version = Object.keys(index)[+!ZIG_VERSION.dev];
183
+ // const version = VERSION; // TODO
184
+ const release = index[version][`${arch}-${platform}`];
170
185
  const url = release.tarball;
171
186
 
172
187
  let base = path.basename(url);
@@ -325,6 +340,7 @@ const downloadImportLib = async () => {
325
340
  const libs = path.join(ROOT, 'build', 'lib');
326
341
  if (fs.existsSync(libs)) {
327
342
  for (const file of fs.readdirSync(libs)) {
343
+ if (!file.startsWith('pkmn')) continue;
328
344
  const type = path.extname(file).slice(1);
329
345
  if (type !== 'node' && type !== 'wasm') continue;
330
346
  // If we don't copy the addon before loading it Windows will return an
@@ -5,8 +5,6 @@ const assert = std.debug.assert;
5
5
 
6
6
  const ERROR: u8 = 0b1100;
7
7
 
8
- const Enum = if (@hasField(std.builtin.Type, "enum")) .@"enum" else .Enum;
9
-
10
8
  pub const OPTIONS: extern struct {
11
9
  showdown: bool,
12
10
  log: bool,
@@ -24,59 +22,59 @@ pub const CHOICES_SIZE = pkmn.CHOICES_SIZE;
24
22
  pub const MAX_LOGS = pkmn.MAX_LOGS;
25
23
  pub const LOGS_SIZE = pkmn.LOGS_SIZE;
26
24
 
27
- pub fn choice_init(choice: u8, data: u8) callconv(.C) u8 {
28
- assert(choice <= @field(@typeInfo(pkmn.Choice.Type), @tagName(Enum)).fields.len);
25
+ pub fn choice_init(choice: u8, data: u8) callconv(.c) u8 {
26
+ assert(choice <= @typeInfo(pkmn.Choice.Type).@"enum".fields.len);
29
27
  assert(data <= 6);
30
28
  return @bitCast(pkmn.Choice{ .type = @enumFromInt(choice), .data = @intCast(data) });
31
29
  }
32
30
 
33
- pub fn choice_type(choice: u8) callconv(.C) u8 {
31
+ pub fn choice_type(choice: u8) callconv(.c) u8 {
34
32
  return @intFromEnum(@as(pkmn.Choice, @bitCast(choice)).type);
35
33
  }
36
34
 
37
- pub fn choice_data(choice: u8) callconv(.C) u8 {
35
+ pub fn choice_data(choice: u8) callconv(.c) u8 {
38
36
  return @as(u8, @as(pkmn.Choice, @bitCast(choice)).data);
39
37
  }
40
38
 
41
- pub fn result_type(result: u8) callconv(.C) u8 {
39
+ pub fn result_type(result: u8) callconv(.c) u8 {
42
40
  return @intFromEnum(@as(pkmn.Result, @bitCast(result)).type);
43
41
  }
44
42
 
45
- pub fn result_p1(result: u8) callconv(.C) u8 {
43
+ pub fn result_p1(result: u8) callconv(.c) u8 {
46
44
  assert(!err(result));
47
45
  return @intFromEnum(@as(pkmn.Result, @bitCast(result)).p1);
48
46
  }
49
47
 
50
- pub fn result_p2(result: u8) callconv(.C) u8 {
48
+ pub fn result_p2(result: u8) callconv(.c) u8 {
51
49
  assert(!err(result));
52
50
  return @intFromEnum(@as(pkmn.Result, @bitCast(result)).p2);
53
51
  }
54
52
 
55
- pub fn err(result: u8) callconv(.C) bool {
53
+ pub fn err(result: u8) callconv(.c) bool {
56
54
  return result == ERROR;
57
55
  }
58
56
 
59
- pub fn psrng_init(prng: *pkmn.PSRNG, seed: u64) callconv(.C) void {
57
+ pub fn psrng_init(prng: *pkmn.PSRNG, seed: u64) callconv(.c) void {
60
58
  prng.src = .{ .seed = seed };
61
59
  }
62
60
 
63
- pub fn psrng_next(prng: *pkmn.PSRNG) callconv(.C) u32 {
61
+ pub fn psrng_next(prng: *pkmn.PSRNG) callconv(.c) u32 {
64
62
  return prng.next();
65
63
  }
66
64
 
67
- pub fn rational_init(rational: *pkmn.Rational(f64)) callconv(.C) void {
65
+ pub fn rational_init(rational: *pkmn.Rational(f64)) callconv(.c) void {
68
66
  rational.reset();
69
67
  }
70
68
 
71
- pub fn rational_reduce(rational: *pkmn.Rational(f64)) callconv(.C) void {
69
+ pub fn rational_reduce(rational: *pkmn.Rational(f64)) callconv(.c) void {
72
70
  rational.reduce();
73
71
  }
74
72
 
75
- pub fn rational_numerator(rational: *const pkmn.Rational(f64)) callconv(.C) f64 {
73
+ pub fn rational_numerator(rational: *const pkmn.Rational(f64)) callconv(.c) f64 {
76
74
  return rational.p;
77
75
  }
78
76
 
79
- pub fn rational_denominator(rational: *const pkmn.Rational(f64)) callconv(.C) f64 {
77
+ pub fn rational_denominator(rational: *const pkmn.Rational(f64)) callconv(.c) f64 {
80
78
  return rational.q;
81
79
  }
82
80
 
@@ -105,7 +103,7 @@ pub fn gen(comptime num: comptime_int) type {
105
103
  };
106
104
 
107
105
  const battle_options = struct {
108
- stream: pkmn.protocol.ByteStream,
106
+ writer: pkmn.protocol.Writer,
109
107
  log: pkmn.protocol.FixedLog,
110
108
  chance: g.Chance(pkmn.Rational(f64)),
111
109
  calc: g.Calc,
@@ -120,13 +118,13 @@ pub fn gen(comptime num: comptime_int) type {
120
118
  log: ?*const log_options,
121
119
  chance: ?*const chance_options,
122
120
  calc: ?*const calc_options,
123
- ) callconv(.C) void {
121
+ ) callconv(.c) void {
124
122
  if (pkmn.options.log) {
125
123
  if (log) |l| {
126
- options.stream = .{ .buffer = l.buf[0..l.len] };
127
- options.log = .{ .writer = options.stream.writer() };
124
+ options.writer = .{ .buffer = l.buf[0..l.len] };
125
+ options.log = .{ .writer = &options.writer };
128
126
  } else {
129
- options.stream.reset();
127
+ options.writer.reset();
130
128
  }
131
129
  }
132
130
  if (pkmn.options.chance) {
@@ -151,25 +149,25 @@ pub fn gen(comptime num: comptime_int) type {
151
149
 
152
150
  pub fn battle_options_chance_probability(
153
151
  options: *battle_options,
154
- ) callconv(.C) *pkmn.Rational(f64) {
152
+ ) callconv(.c) *pkmn.Rational(f64) {
155
153
  return &options.chance.probability;
156
154
  }
157
155
 
158
156
  pub fn battle_options_chance_actions(
159
157
  options: *battle_options,
160
- ) callconv(.C) *g.chance.Actions {
158
+ ) callconv(.c) *g.chance.Actions {
161
159
  return &options.chance.actions;
162
160
  }
163
161
 
164
162
  pub fn battle_options_chance_durations(
165
163
  options: *battle_options,
166
- ) callconv(.C) *g.chance.Durations {
164
+ ) callconv(.c) *g.chance.Durations {
167
165
  return &options.chance.durations;
168
166
  }
169
167
 
170
168
  pub fn battle_options_calc_summaries(
171
169
  options: *battle_options,
172
- ) callconv(.C) *g.calc.Summaries {
170
+ ) callconv(.c) *g.calc.Summaries {
173
171
  return &options.calc.summaries;
174
172
  }
175
173
 
@@ -178,7 +176,7 @@ pub fn gen(comptime num: comptime_int) type {
178
176
  c1: pkmn.Choice,
179
177
  c2: pkmn.Choice,
180
178
  opts: ?*battle_options,
181
- ) callconv(.C) pkmn.Result {
179
+ ) callconv(.c) pkmn.Result {
182
180
  if ((pkmn.options.log or pkmn.options.chance or pkmn.options.calc) and opts != null) {
183
181
  return battle.update(c1, c2, opts.?) catch return @bitCast(ERROR);
184
182
  }
@@ -191,64 +189,12 @@ pub fn gen(comptime num: comptime_int) type {
191
189
  request: u8,
192
190
  out: [*]u8,
193
191
  n: usize,
194
- ) callconv(.C) u8 {
195
- assert(player <= @field(@typeInfo(pkmn.Player), @tagName(Enum)).fields.len);
196
- assert(request <= @field(@typeInfo(pkmn.Choice.Type), @tagName(Enum)).fields.len);
192
+ ) callconv(.c) u8 {
193
+ assert(player <= @typeInfo(pkmn.Player).@"enum".fields.len);
194
+ assert(request <= @typeInfo(pkmn.Choice.Type).@"enum".fields.len);
197
195
 
198
196
  assert(!pkmn.options.showdown or n > 0);
199
197
  return battle.choices(@enumFromInt(player), @enumFromInt(request), @ptrCast(out[0..n]));
200
198
  }
201
199
  };
202
200
  }
203
-
204
- pub fn exports() type {
205
- @export(choice_init, .{ .name = "pkmn_choice_init", .linkage = .Strong });
206
- @export(choice_type, .{ .name = "pkmn_choice_type", .linkage = .Strong });
207
- @export(choice_data, .{ .name = "pkmn_choice_data", .linkage = .Strong });
208
-
209
- @export(result_type, .{ .name = "pkmn_result_type", .linkage = .Strong });
210
- @export(result_p1, .{ .name = "pkmn_result_p1", .linkage = .Strong });
211
- @export(result_p2, .{ .name = "pkmn_result_p2", .linkage = .Strong });
212
-
213
- @export(err, .{ .name = "pkmn_error", .linkage = .Strong });
214
-
215
- @export(psrng_init, .{ .name = "pkmn_psrng_init", .linkage = .Strong });
216
- @export(psrng_next, .{ .name = "pkmn_psrng_next", .linkage = .Strong });
217
-
218
- @export(rational_init, .{ .name = "pkmn_rational_init", .linkage = .Strong });
219
- @export(rational_reduce, .{ .name = "pkmn_rational_reduce", .linkage = .Strong });
220
- @export(rational_numerator, .{ .name = "pkmn_rational_numerator", .linkage = .Strong });
221
- @export(rational_denominator, .{ .name = "pkmn_rational_denominator", .linkage = .Strong });
222
-
223
- @export(
224
- gen(1).battle_options_set,
225
- .{ .name = "pkmn_gen1_battle_options_set", .linkage = .Strong },
226
- );
227
- @export(
228
- gen(1).battle_options_chance_probability,
229
- .{ .name = "pkmn_gen1_battle_options_chance_probability", .linkage = .Strong },
230
- );
231
- @export(
232
- gen(1).battle_options_chance_actions,
233
- .{ .name = "pkmn_gen1_battle_options_chance_actions", .linkage = .Strong },
234
- );
235
- @export(
236
- gen(1).battle_options_chance_durations,
237
- .{ .name = "pkmn_gen1_battle_options_chance_durations", .linkage = .Strong },
238
- );
239
- @export(
240
- gen(1).battle_options_calc_summaries,
241
- .{ .name = "pkmn_gen1_battle_options_calc_summaries", .linkage = .Strong },
242
- );
243
-
244
- @export(
245
- gen(1).battle_update,
246
- .{ .name = "pkmn_gen1_battle_update", .linkage = .Strong },
247
- );
248
- @export(
249
- gen(1).battle_choices,
250
- .{ .name = "pkmn_gen1_battle_choices", .linkage = .Strong },
251
- );
252
-
253
- return struct {};
254
- }
@@ -1,14 +1,10 @@
1
+ const c = @import("napi");
1
2
  const js = @import("../common/js.zig");
2
3
  const pkmn = @import("../pkmn.zig");
3
4
  const std = @import("std");
4
5
 
5
6
  const assert = std.debug.assert;
6
7
 
7
- const c = @cImport({
8
- @cDefine("NAPI_VERSION", "8");
9
- @cInclude("node_api.h");
10
- });
11
-
12
8
  pub fn register(env: c.napi_env) c.napi_value {
13
9
  const object = js.Object.init(env);
14
10
  const properties = [_]c.napi_property_descriptor{
@@ -53,7 +49,7 @@ fn bind(env: c.napi_env, gen: anytype) c.napi_value {
53
49
 
54
50
  fn update(gen: anytype) c.napi_callback {
55
51
  return struct {
56
- fn call(env: c.napi_env, info: c.napi_callback_info) callconv(.C) c.napi_value {
52
+ fn call(env: c.napi_env, info: c.napi_callback_info) callconv(.c) c.napi_value {
57
53
  var argc: usize = 4;
58
54
  var argv: [4]c.napi_value = undefined;
59
55
  assert(c.napi_get_cb_info(env, info, &argc, &argv, null, null) == c.napi_ok);
@@ -64,7 +60,7 @@ fn update(gen: anytype) c.napi_callback {
64
60
  assert(c.napi_get_arraybuffer_info(env, argv[0], &data, &len) == c.napi_ok);
65
61
  assert(len == @sizeOf(gen.Battle(gen.PRNG)));
66
62
 
67
- var battle: *gen.Battle(gen.PRNG) = @alignCast(@ptrCast(data.?));
63
+ var battle: *gen.Battle(gen.PRNG) = @ptrCast(@alignCast(data.?));
68
64
  const c1: pkmn.Choice = @bitCast(js.Number.get(env, argv[1], u8));
69
65
  const c2: pkmn.Choice = @bitCast(js.Number.get(env, argv[2], u8));
70
66
 
@@ -77,10 +73,10 @@ fn update(gen: anytype) c.napi_callback {
77
73
  assert(len == gen.LOGS_SIZE);
78
74
 
79
75
  const buf = @as([*]u8, @ptrCast(data.?))[0..gen.LOGS_SIZE];
80
- var stream: pkmn.protocol.ByteStream = .{ .buffer = buf };
76
+ var writer: pkmn.protocol.Writer = .{ .buffer = buf };
81
77
  // TODO: extract out
82
78
  var opts = pkmn.battle.options(
83
- pkmn.protocol.FixedLog{ .writer = stream.writer() },
79
+ pkmn.protocol.FixedLog{ .writer = &writer },
84
80
  gen.chance.NULL,
85
81
  gen.calc.NULL,
86
82
  );
@@ -95,7 +91,7 @@ fn update(gen: anytype) c.napi_callback {
95
91
 
96
92
  fn choices(gen: anytype) c.napi_callback {
97
93
  return struct {
98
- fn call(env: c.napi_env, info: c.napi_callback_info) callconv(.C) c.napi_value {
94
+ fn call(env: c.napi_env, info: c.napi_callback_info) callconv(.c) c.napi_value {
99
95
  var argc: usize = 4;
100
96
  var argv: [4]c.napi_value = undefined;
101
97
  assert(c.napi_get_cb_info(env, info, &argc, &argv, null, null) == c.napi_ok);
@@ -106,7 +102,7 @@ fn choices(gen: anytype) c.napi_callback {
106
102
  assert(c.napi_get_arraybuffer_info(env, argv[0], &data, &len) == c.napi_ok);
107
103
  assert(len == @sizeOf(gen.Battle(gen.PRNG)));
108
104
 
109
- var battle: *gen.Battle(gen.PRNG) = @alignCast(@ptrCast(data.?));
105
+ var battle: *gen.Battle(gen.PRNG) = @ptrCast(@alignCast(data.?));
110
106
  const player: pkmn.Player = @enumFromInt(js.Number.get(env, argv[1], u8));
111
107
  const request: pkmn.Choice.Type = @enumFromInt(js.Number.get(env, argv[2], u8));
112
108
 
@@ -3,9 +3,6 @@ const std = @import("std");
3
3
 
4
4
  const assert = std.debug.assert;
5
5
 
6
- const Enum = if (@hasField(std.builtin.Type, "enum")) .@"enum" else .Enum;
7
- const Strong = if (@hasField(std.builtin.GlobalLinkage, "strong")) .strong else .Strong;
8
-
9
6
  pub const options = pkmn.options;
10
7
 
11
8
  pub fn gen(comptime num: comptime_int) type {
@@ -19,13 +16,13 @@ pub fn gen(comptime num: comptime_int) type {
19
16
  c1: pkmn.Choice,
20
17
  c2: pkmn.Choice,
21
18
  options_: ?[*]u8,
22
- ) callconv(.C) pkmn.Result {
19
+ ) callconv(.c) pkmn.Result {
23
20
  return (if (options_) |o| result: {
24
21
  const buf = @as([*]u8, @ptrCast(o))[0..g.LOGS_SIZE];
25
- var stream: pkmn.protocol.ByteStream = .{ .buffer = buf };
22
+ var writer: pkmn.protocol.Writer = .{ .buffer = buf };
26
23
  // TODO: extract out
27
24
  var opts = pkmn.battle.options(
28
- pkmn.protocol.FixedLog{ .writer = stream.writer() },
25
+ pkmn.protocol.FixedLog{ .writer = &writer },
29
26
  g.chance.NULL,
30
27
  g.calc.NULL,
31
28
  );
@@ -38,9 +35,9 @@ pub fn gen(comptime num: comptime_int) type {
38
35
  player: u8,
39
36
  request: u8,
40
37
  buf: [*]u8,
41
- ) callconv(.C) u8 {
42
- assert(player <= @field(@typeInfo(pkmn.Player), @tagName(Enum)).fields.len);
43
- assert(request <= @field(@typeInfo(pkmn.Choice.Type), @tagName(Enum)).fields.len);
38
+ ) callconv(.c) u8 {
39
+ assert(player <= @typeInfo(pkmn.Player).@"enum".fields.len);
40
+ assert(request <= @typeInfo(pkmn.Choice.Type).@"enum".fields.len);
44
41
 
45
42
  const n = CHOICES_SIZE;
46
43
  return battle.choices(@enumFromInt(player), @enumFromInt(request), @ptrCast(buf[0..n]));
@@ -48,12 +45,6 @@ pub fn gen(comptime num: comptime_int) type {
48
45
  };
49
46
  }
50
47
 
51
- pub fn exports() type {
52
- @export(gen(1).update, .{ .name = "GEN1_update", .linkage = Strong });
53
- @export(gen(1).choices, .{ .name = "GEN1_choices", .linkage = Strong });
54
- return struct {};
55
- }
56
-
57
48
  fn size(n: usize) u32 {
58
49
  return std.math.ceilPowerOfTwo(u32, @as(u32, @intCast(n))) catch unreachable;
59
50
  }
@@ -3,19 +3,12 @@ const std = @import("std");
3
3
  const expectEqual = std.testing.expectEqual;
4
4
  const assert = std.debug.assert;
5
5
 
6
- const Int = if (@hasField(std.builtin.Type, "int")) .int else .Int;
7
- const Enum = if (@hasField(std.builtin.Type, "enum")) .@"enum" else .Enum;
8
-
9
6
  /// Helpers for working with bit-packed arrays of non-powers-of-2 types.
10
7
  /// NOTE: ziglang/zig#12547
11
8
  pub fn Array(comptime n: comptime_int, comptime U: type) type {
12
9
  return struct {
13
10
  const size = @bitSizeOf(U);
14
- const options: std.builtin.Type.Int = .{ .signedness = .unsigned, .bits = size * n };
15
- pub const T = @Type(if (@hasField(std.builtin.Type, "int"))
16
- .{ .int = options }
17
- else
18
- .{ .Int = options });
11
+ pub const T = @Int(.unsigned, size * n);
19
12
 
20
13
  /// Returns the value stored at index `i` in the array `a`.
21
14
  pub fn get(a: T, i: usize) U {
@@ -24,8 +17,8 @@ pub fn Array(comptime n: comptime_int, comptime U: type) type {
24
17
  const mask: T = (1 << size) - 1;
25
18
  const result = (a >> @intCast(shift)) & mask;
26
19
  return switch (@typeInfo(U)) {
27
- Enum => @enumFromInt(result),
28
- Int => @intCast(result),
20
+ .@"enum" => @enumFromInt(result),
21
+ .int => @intCast(result),
29
22
  else => unreachable,
30
23
  };
31
24
  }
@@ -34,8 +27,8 @@ pub fn Array(comptime n: comptime_int, comptime U: type) type {
34
27
  pub fn set(a: T, i: usize, val: U) T {
35
28
  assert(i < n);
36
29
  const v: T = switch (@typeInfo(U)) {
37
- Enum => @intFromEnum(val),
38
- Int => @intCast(val),
30
+ .@"enum" => @intFromEnum(val),
31
+ .int => @intCast(val),
39
32
  else => unreachable,
40
33
  };
41
34
  const shift = i * size;
@@ -1,27 +1,20 @@
1
+ const builtin = @import("builtin");
1
2
  const std = @import("std");
2
3
 
3
4
  const debug = std.debug;
4
- const io = std.io;
5
-
6
- const Array = if (@hasField(std.builtin.Type, "array")) .array else .Array;
7
- const Enum = if (@hasField(std.builtin.Type, "enum")) .@"enum" else .Enum;
8
- const Optional = if (@hasField(std.builtin.Type, "optional")) .optional else .Optional;
9
- const Pointer = if (@hasField(std.builtin.Type, "pointer")) .pointer else .Pointer;
10
- const Struct = if (@hasField(std.builtin.Type, "struct")) .@"struct" else .Struct;
11
- const Union = if (@hasField(std.builtin.Type, "union")) .@"union" else .Union;
12
5
 
13
6
  pub fn print(value: anytype) void {
14
- if (@hasDecl(debug, "lockStdErr")) debug.lockStdErr() else debug.getStderrMutex().lock();
15
- defer if (@hasDecl(debug, "unlockStdErr"))
16
- debug.unlockStdErr()
17
- else
18
- debug.getStderrMutex().unlock();
19
- const stderr = io.getStdErr().writer();
7
+ if (builtin.target.os.tag == .freestanding) return;
8
+
9
+ var buffer: [4096]u8 = undefined;
10
+ const stderr = debug.lockStderr(&buffer);
11
+ defer debug.unlockStderr();
12
+ var fw = stderr.file_writer;
20
13
 
21
14
  nosuspend {
22
- stderr.writeAll("\x1b[41m") catch return;
15
+ fw.interface.writeAll("\x1b[41m") catch return;
23
16
  if (@TypeOf(@src()) == @TypeOf(value)) {
24
- stderr.print("{s} ({s}:{d}:{d})", .{
17
+ fw.interface.print("{s} ({s}:{d}:{d})", .{
25
18
  value.fn_name,
26
19
  value.file,
27
20
  value.line,
@@ -29,77 +22,58 @@ pub fn print(value: anytype) void {
29
22
  }) catch return;
30
23
  } else {
31
24
  switch (@typeInfo(@TypeOf(value))) {
32
- Struct => |info| {
25
+ .@"struct" => |info| {
33
26
  if (info.is_tuple) {
34
27
  inline for (info.fields, 0..) |f, i| {
35
- inspect(@field(value, f.name));
36
- if (i < info.fields.len - 1) stderr.writeAll(" ") catch return;
28
+ inspect(fw, @field(value, f.name));
29
+ if (i < info.fields.len - 1) fw.interface.writeAll(" ") catch return;
37
30
  }
38
31
  } else {
39
- inspect(value);
32
+ inspect(fw, value);
40
33
  }
41
34
  },
42
- else => inspect(value),
35
+ else => inspect(fw, value),
43
36
  }
44
37
  }
45
- stderr.writeAll("\x1b[K\x1b[0m\n") catch return;
38
+ fw.interface.writeAll("\x1b[K\x1b[0m\n") catch return;
46
39
  }
47
40
  }
48
41
 
49
- fn inspect(value: anytype) void {
50
- const stderr = io.getStdErr().writer();
51
-
42
+ fn inspect(w: anytype, value: anytype) void {
52
43
  nosuspend {
53
44
  const err = "Unable to format type '" ++ @typeName(@TypeOf(value)) ++ "'";
54
45
  switch (@typeInfo(@TypeOf(value))) {
55
- Array => |info| {
56
- if (info.child == u8) return stderr.print("{s}", .{value}) catch return;
46
+ .array => |info| {
47
+ if (info.child == u8) return w.interface.print("{s}", .{value}) catch return;
57
48
  @compileError(err);
58
49
  },
59
- Pointer => |ptr_info| switch (ptr_info.size) {
60
- .One => switch (@typeInfo(ptr_info.child)) {
61
- Array => |info| {
62
- if (info.child == u8) return stderr.print("{s}", .{value}) catch return;
50
+ .pointer => |ptr_info| switch (ptr_info.size) {
51
+ .one => switch (@typeInfo(ptr_info.child)) {
52
+ .array => |info| {
53
+ if (info.child == u8) {
54
+ return w.interface.print("{s}", .{value}) catch return;
55
+ }
63
56
  @compileError(err);
64
57
  },
65
- Enum, Union, Struct => return inspect(value.*),
58
+ .@"enum", .@"union", .@"struct" => return inspect(value.*),
66
59
  else => @compileError(err),
67
60
  },
68
- .Many, .C => {
61
+ .many, .c => {
69
62
  if (ptr_info.sentinel) |_| return inspect(std.mem.span(value));
70
63
  if (ptr_info.child == u8) {
71
- return stderr.print("{s}", .{std.mem.span(value)}) catch return;
64
+ return w.interface.print("{s}", .{std.mem.span(value)}) catch return;
72
65
  }
73
66
  @compileError(err);
74
67
  },
75
- .Slice => {
76
- if (ptr_info.child == u8) return stderr.print("{s}", .{value}) catch return;
68
+ .slice => {
69
+ if (ptr_info.child == u8) {
70
+ return w.interface.print("{s}", .{value}) catch return;
71
+ }
77
72
  @compileError(err);
78
73
  },
79
74
  },
80
- Optional => stderr.print("{?}", .{value}) catch return,
81
- else => stderr.print("{}", .{value}) catch return,
75
+ .optional => w.interface.print("{?}", .{value}) catch return,
76
+ else => w.interface.print("{}", .{value}) catch return,
82
77
  }
83
78
  }
84
79
  }
85
-
86
- const showdown = @import("./options.zig").showdown;
87
- const Result = @import("./data.zig").Result;
88
- const Choice = @import("./data.zig").Choice;
89
-
90
- pub fn dump(gen: u8, battle: anytype, frame: ?struct { Result, Choice, Choice }) void {
91
- const file = std.fs.cwd().createFile("logs/dump.bin", .{}) catch return;
92
- defer file.close();
93
- var w = file.writer();
94
- w.writeByte(@intFromBool(showdown)) catch return;
95
- w.writeByte(gen) catch return;
96
- w.writeInt(i16, 0, .little) catch return;
97
- w.writeInt(i32, 0, .little) catch return;
98
- w.writeStruct(battle) catch return;
99
- w.writeStruct(battle) catch return;
100
- if (frame) |f| {
101
- w.writeStruct(f[0]) catch return;
102
- w.writeStruct(f[1]) catch return;
103
- w.writeStruct(f[2]) catch return;
104
- }
105
- }