@eveshipfit/dogma-engine 11.1.0 → 12.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -199,15 +199,25 @@ The WebAssembly variant is published on npm as
199
199
  [`@eveshipfit/dogma-engine`](https://www.npmjs.com/package/@eveshipfit/dogma-engine).
200
200
  [`@eveshipfit/sde`](https://www.npmjs.com/package/@eveshipfit/sde) ships `sde.dat` in its `dist` folder; serve or bundle that file.
201
201
 
202
+ The package is an ES module with TypeScript types included, and it runs anywhere: under a bundler
203
+ (Vite, webpack, ...), from a CDN, or in a plain `<script type="module">`.
204
+ Its default export loads the WebAssembly and has to be awaited once before any other function is called.
205
+
202
206
  ```bash
203
207
  npm install @eveshipfit/dogma-engine @eveshipfit/sde
204
208
  ```
205
209
 
206
210
  ```js
207
- import init, { init as initPanicHook, load_sde, load_eft, calculate, validate, beacon } from "@eveshipfit/dogma-engine";
211
+ import wasmInit, {
212
+ load_sde,
213
+ load_eft,
214
+ save_eft,
215
+ calculate,
216
+ validate,
217
+ beacon,
218
+ } from "@eveshipfit/dogma-engine";
208
219
 
209
- await init();
210
- initPanicHook();
220
+ await wasmInit();
211
221
 
212
222
  const sde = await fetch("/sde.dat").then((response) => response.arrayBuffer());
213
223
  const buildNumber = load_sde(new Uint8Array(sde));
@@ -224,6 +234,8 @@ const withSources = calculate(fit, { sources: true });
224
234
  const withBeacon = calculate({ ...fit, incoming: beacon(beaconTypeId) });
225
235
  /* Or if you have an EFT, the text format EVE copies a fit to the clipboard in: */
226
236
  const imported = calculate(load_eft("[Rifter, My Rifter]\n200mm AutoCannon I"));
237
+ /* And to write a fit back out as EFT: */
238
+ const eft = save_eft(fit);
227
239
 
228
240
  /* What EVE would not let you fly; it calculates the fit itself: */
229
241
  const violations = validate(fit);
@@ -265,6 +277,8 @@ with_sources = dogma.calculate(fit, {"sources": True})
265
277
  with_beacon = dogma.calculate({**fit, "incoming": dogma.beacon(beacon_type_id)})
266
278
  # Or if you have an EFT, the text format EVE copies a fit to the clipboard in:
267
279
  imported = dogma.calculate(dogma.load_eft("[Rifter, My Rifter]\n200mm AutoCannon I"))
280
+ # And to write a fit back out as EFT:
281
+ eft = dogma.save_eft(fit)
268
282
 
269
283
  # What EVE would not let you fly; it calculates the fit itself:
270
284
  violations = dogma.validate(fit)
@@ -307,6 +321,13 @@ printf '[Nergal, Spool]\nLight Entropic Disintegrator II, Occult S\n' \
307
321
 
308
322
  It prints a table on a terminal and JSON otherwise; see `--help` for the rest.
309
323
 
324
+ Or to write the fit back out as EFT, instead of calculating it:
325
+
326
+ ```bash
327
+ printf '[Nergal, Spool]\nLight Entropic Disintegrator II, Occult S\n' \
328
+ | cargo run --release -p esf-cli -- --eft
329
+ ```
330
+
310
331
  The regression suite reads the same paths; set `ESF_SDE` and `ESF_NAMES` to point it elsewhere.
311
332
 
312
333
  ## Regression
@@ -346,7 +367,7 @@ This is done with [wasm-pack](https://rustwasm.github.io/wasm-pack/):
346
367
 
347
368
  ```bash
348
369
  cargo install wasm-pack
349
- wasm-pack build crates/esf-wasm --release --out-dir ../../pkg
370
+ wasm-pack build crates/esf-wasm --release --target web --out-dir ../../pkg
350
371
  ```
351
372
 
352
373
  In the `pkg` folder is now a NPM module to use.
@@ -1,23 +1,446 @@
1
1
  /* tslint:disable */
2
2
  /* eslint-disable */
3
+ /**
4
+ * A charge loaded in a module.
5
+ */
6
+ export interface Charge {
7
+ /**
8
+ * The type id of the charge.
9
+ */
10
+ type_id: number;
11
+ }
12
+
13
+ /**
14
+ * A module, drone, fighter squadron, implant, booster or item in cargo.
15
+ */
16
+ export interface FitItem {
17
+ /**
18
+ * The type id of the item.
19
+ */
20
+ type_id: number;
21
+ /**
22
+ * Where the item is.
23
+ */
24
+ slot: Slot;
25
+ /**
26
+ * 1 for modules. Stack size for drones, fighters and cargo; for fighters
27
+ * in a tube, the size of the squadron.
28
+ */
29
+ quantity?: number;
30
+ /**
31
+ * The state asked for; the calculation lowers it when the item cannot
32
+ * reach it.
33
+ */
34
+ state: State;
35
+ /**
36
+ * The charge loaded in the module, if any.
37
+ */
38
+ charge?: Charge;
39
+ /**
40
+ * Only for mutated modules and drones.
41
+ */
42
+ mutation?: Mutation;
43
+ /**
44
+ * Only for fighters: the abilities used, by effect id. `None` uses the
45
+ * abilities the fighter uses by default.
46
+ */
47
+ fighter_abilities?: number[];
48
+ /**
49
+ * Only for boosters: the side effects rolled, by effect id. Empty means
50
+ * none.
51
+ */
52
+ booster_side_effects?: number[];
53
+ /**
54
+ * How far a module whose bonus grows every cycle has spooled.
55
+ * Only per-second stats use it; volley is always unspooled.
56
+ * `None` is fully spooled.
57
+ */
58
+ spool?: Spool;
59
+ }
60
+
61
+ /**
62
+ * A projected buff (like command bursts).
63
+ */
64
+ export interface ProjectedBuff {
65
+ /**
66
+ * Which buff, as `dbuffCollections` in the SDE numbers them.
67
+ */
68
+ id: number;
69
+ /**
70
+ * How strong it is, in whatever the buff's operation reads.
71
+ */
72
+ value: number;
73
+ }
74
+
75
+ /**
76
+ * A projected dogma effect.
77
+ */
78
+ export interface ProjectedEffect {
79
+ /**
80
+ * The type the effect belongs to.
81
+ */
82
+ type_id: number;
83
+ /**
84
+ * Which effect, as `dogmaEffects` in the SDE numbers them.
85
+ */
86
+ effect_id: number;
87
+ /**
88
+ * Every attribute and its value the effect reads.
89
+ */
90
+ attributes?: Map<number, number> | Record<number, number>;
91
+ }
92
+
93
+ /**
94
+ * A rack of slots, or a hardpoint a weapon needs.
95
+ */
96
+ export type SlotKind = "high" | "medium" | "low" | "rig" | "subsystem" | "service" | "turret" | "launcher";
97
+
98
+ /**
99
+ * A resource the ship only has so much of.
100
+ */
101
+ export type Resource = "cpu" | "powergrid" | "calibration" | "drone_bay" | "drone_bandwidth" | "launched_drones" | "fighter_bay" | "fighter_tubes" | "light_fighter_tubes" | "support_fighter_tubes" | "heavy_fighter_tubes" | "cargo_bay" | "charge_capacity";
102
+
103
+ /**
104
+ * A rule of EVE's, and the values that failed it.
105
+ *
106
+ * What an item would accept instead is not repeated here; it is on the item
107
+ * itself, as `chargeGroup1`, `canFitShipType1` and the like.
108
+ */
109
+ export type Rule = { type: "resource"; resource: Resource; used: number; available: number } | { type: "slots"; slot: SlotKind; used: number; available: number } | { type: "wrong_slot"; expected: SlotKind } | { type: "slot_taken" } | { type: "wrong_slot_index"; expected: number } | { type: "subsystem_taken" } | { type: "skill"; type_id: number; required: number; level: number } | { type: "rig_size"; ship: number; item: number } | { type: "ship_restricted" } | { type: "capital_item" } | { type: "structure_item" } | { type: "ship_item" } | { type: "max_group"; group_id: number; limit: GroupLimit; used: number; allowed: number } | { type: "max_type"; type_id: number; used: number; allowed: number } | { type: "charge_group" } | { type: "charge_size"; module: number; charge: number };
110
+
111
+ /**
112
+ * A ship, what is fitted to it, and the character flying it.
113
+ */
114
+ export interface Fit {
115
+ /**
116
+ * Only for display; the calculation does not use it.
117
+ */
118
+ name?: string;
119
+ /**
120
+ * The ship.
121
+ */
122
+ ship: Ship;
123
+ /**
124
+ * Modules, drones, fighters, implants, boosters and cargo.
125
+ */
126
+ items: FitItem[];
127
+ /**
128
+ * The character flying the ship.
129
+ */
130
+ character?: Character;
131
+ /**
132
+ * Where the ship is.
133
+ */
134
+ environment?: Environment;
135
+ /**
136
+ * What projections to apply on this fit.
137
+ */
138
+ incoming?: Projection;
139
+ }
140
+
141
+ /**
142
+ * How a modifier changes an attribute. They are applied in this order.
143
+ */
144
+ export type EffectOperator = "pre_assign" | "pre_mul" | "pre_div" | "mod_add" | "mod_sub" | "post_mul" | "post_div" | "post_percent" | "post_assign";
145
+
146
+ /**
147
+ * How a module or drone was mutated.
148
+ */
149
+ export interface Mutation {
150
+ /**
151
+ * The type id of the item before it was mutated.
152
+ */
153
+ base: number;
154
+ /**
155
+ * The rolled value of each mutated attribute, by attribute id.
156
+ */
157
+ attributes?: Map<number, number> | Record<number, number>;
158
+ }
159
+
160
+ /**
161
+ * How far a module has spooled.
162
+ */
163
+ export type Spool = { multiplier_bonus: number };
164
+
165
+ /**
166
+ * How incoming damage is split over the four damage types. Only the ratio
167
+ * matters; the calculation scales the four to add up to one.
168
+ */
169
+ export interface DamageProfile {
170
+ /**
171
+ * EM damage.
172
+ */
173
+ em?: number;
174
+ /**
175
+ * Explosive damage.
176
+ */
177
+ explosive?: number;
178
+ /**
179
+ * Kinetic damage.
180
+ */
181
+ kinetic?: number;
182
+ /**
183
+ * Thermal damage.
184
+ */
185
+ thermal?: number;
186
+ }
187
+
188
+ /**
189
+ * One attribute, before and after the effects on it.
190
+ */
191
+ export interface AttributeValue {
192
+ /**
193
+ * The value from the SDE.
194
+ */
195
+ base: number;
196
+ /**
197
+ * The value after every effect is applied.
198
+ */
199
+ value: number;
200
+ /**
201
+ * In the order pass 3 applied them; empty unless `Options::sources` is set.
202
+ */
203
+ sources?: Source[];
204
+ }
205
+
206
+ /**
207
+ * One modifier on an attribute, and where it came from.
208
+ */
209
+ export interface Source {
210
+ /**
211
+ * The object the effect belongs to.
212
+ */
213
+ from: SourceRef;
214
+ /**
215
+ * The effect that holds the modifier; `None` for a buff, which has none.
216
+ */
217
+ effect_id: number | undefined;
218
+ /**
219
+ * The attribute on the source that holds `value`; `None` for a buff,
220
+ * which carries its own strength.
221
+ */
222
+ source_attribute_id: number | undefined;
223
+ /**
224
+ * How `value` changes the attribute.
225
+ */
226
+ operator: EffectOperator;
227
+ /**
228
+ * The source attribute's value, as pass 3 used it.
229
+ */
230
+ value: number;
231
+ /**
232
+ * A penalised stack is split into one entry per item, as each gets its own penalty.
233
+ */
234
+ quantity: number;
235
+ /**
236
+ * The stacking penalty factor applied; `None` when not penalised.
237
+ */
238
+ penalty: number | undefined;
239
+ /**
240
+ * False when the source's state is too low for the effect.
241
+ */
242
+ applied: boolean;
243
+ }
244
+
245
+ /**
246
+ * One rule the fit breaks, and what breaks it.
247
+ */
248
+ export interface Violation {
249
+ /**
250
+ * What the rule is about.
251
+ */
252
+ target: Target;
253
+ /**
254
+ * The rule, and the values that failed it.
255
+ */
256
+ rule: Rule;
257
+ }
258
+
259
+ /**
260
+ * The calculated attributes of the ship, its mode, the character, or one item.
261
+ */
262
+ export interface ItemResult {
263
+ /**
264
+ * Every attribute, by attribute id.
265
+ */
266
+ attributes: Map<number, AttributeValue>;
267
+ /**
268
+ * The state actually reached, which may be below what was requested.
269
+ */
270
+ state: State;
271
+ /**
272
+ * The highest state the item can reach.
273
+ */
274
+ max_state: State;
275
+ /**
276
+ * The charge loaded in the module, if any.
277
+ */
278
+ charge: ItemResult | undefined;
279
+ }
280
+
281
+ /**
282
+ * The character flying the ship.
283
+ */
284
+ export interface Character {
285
+ /**
286
+ * The level of each skill, by type id. A skill that is not listed is not
287
+ * trained, and gives no bonus.
288
+ */
289
+ skills?: Map<number, number> | Record<number, number>;
290
+ /**
291
+ * -10.0 to 5.0. Only a few ships have a bonus that scales with it.
292
+ */
293
+ security_status?: number;
294
+ }
295
+
296
+ /**
297
+ * The external buffs and effects that can be applied to another ship.
298
+ *
299
+ * A calculation reports what the fit hands out; put that in
300
+ * [`Fit::incoming`](crate::Fit::incoming) of another fit to have it applied.
301
+ */
302
+ export interface Projection {
303
+ /**
304
+ * Buffs, like command burst hands.
305
+ */
306
+ buffs?: ProjectedBuff[];
307
+ /**
308
+ * Effects, like webifiers, remote reps, etc.
309
+ */
310
+ effects?: ProjectedEffect[];
311
+ }
312
+
313
+ /**
314
+ * The result of [`calculate()`](crate::calculate).
315
+ */
316
+ export interface Calculation {
317
+ /**
318
+ * The ship.
319
+ */
320
+ ship: ItemResult;
321
+ /**
322
+ * The active mode, if the ship has one.
323
+ */
324
+ mode?: ItemResult;
325
+ /**
326
+ * Index-parallel to `Fit::items`: same length, same order.
327
+ */
328
+ items: ItemResult[];
329
+ /**
330
+ * The character.
331
+ */
332
+ character: ItemResult;
333
+ /**
334
+ * The buffs that landed, ordered by id: those of `Fit::incoming`, plus
335
+ * the ones the fit's own bursts hand out. What is missing lost to another
336
+ * source of the same buff, or the SDE has no such buff.
337
+ */
338
+ buffs?: ProjectedBuff[];
339
+ /**
340
+ * All outgoing projections (effects and buffs).
341
+ */
342
+ outgoing?: Projection;
343
+ }
344
+
345
+ /**
346
+ * The security of a solar system.
347
+ */
348
+ export type Security = "high_sec" | "low_sec" | "null_sec" | "wormhole";
349
+
350
+ /**
351
+ * The ship of a fit.
352
+ */
353
+ export interface Ship {
354
+ /**
355
+ * The type id of the ship.
356
+ */
357
+ type_id: number;
358
+ /**
359
+ * The type id of the active mode, for ships that have modes.
360
+ */
361
+ mode?: number;
362
+ }
363
+
364
+ /**
365
+ * The state of an item, lowest first.
366
+ */
367
+ export type State = "offline" | "online" | "active" | "overload";
368
+
369
+ /**
370
+ * What [`calculate()`] reports on top of the values.
371
+ */
372
+ export interface Options {
373
+ /**
374
+ * Report per attribute the modifiers its value was calculated from.
375
+ */
376
+ sources?: boolean;
377
+ }
378
+
379
+ /**
380
+ * What a Reactive Armor Hardener shifts its resistances towards.
381
+ *
382
+ * EVE shows it as a plain 15/15/15/15 hardener, as the client has no damage
383
+ * to shift it against. `DoNotAdapt` reports the same, and is the default.
384
+ */
385
+ export type ReactiveArmor = "do_not_adapt" | "damage_profile" | { profile: DamageProfile };
386
+
387
+ /**
388
+ * What a [`Violation`] is about. `Item` and `Charge` index into `Fit::items`.
389
+ */
390
+ export type Target = { type: "ship" } | { type: "item"; index: number } | { type: "charge"; index: number };
391
+
392
+ /**
393
+ * Where an item is. The number is the position in its rack, starting at 0;
394
+ * for implants and boosters, the slot as EVE numbers it, starting at 1.
395
+ */
396
+ export type Slot = { type: "high"; index: number } | { type: "medium"; index: number } | { type: "low"; index: number } | { type: "rig"; index: number } | { type: "subsystem"; index: number } | { type: "service"; index: number } | { type: "fighter_tube"; index: number } | { type: "fighter_bay" } | { type: "implant"; index: number } | { type: "booster"; index: number } | { type: "drone_bay" } | { type: "cargo" };
397
+
398
+ /**
399
+ * Where the ship is.
400
+ */
401
+ export interface Environment {
402
+ /**
403
+ * The damage the ship is assumed to take, for effective hitpoints.
404
+ */
405
+ damage_profile?: DamageProfile;
406
+ /**
407
+ * The security of the solar system.
408
+ */
409
+ security?: Security;
410
+ /**
411
+ * What a Reactive Armor Hardener shifts its resistances towards.
412
+ */
413
+ reactive_armor?: ReactiveArmor;
414
+ }
415
+
416
+ /**
417
+ * Which state a group limit counts.
418
+ */
419
+ export type GroupLimit = "fitted" | "online" | "active";
420
+
421
+ /**
422
+ * `Item` and `Charge` index into `Fit::items`, `Projected` into
423
+ * `Fit::incoming.effects`. A skill and a buff are not in the result, so they
424
+ * carry their own id.
425
+ */
426
+ export type SourceRef = { type: "ship" } | { type: "mode" } | { type: "character" } | { type: "item"; index: number } | { type: "charge"; index: number } | { type: "skill"; type_id: number } | { type: "projected"; index: number } | { type: "buff"; id: number };
427
+
3
428
 
4
429
  /**
5
430
  * What a beacon in space hands to every fit in there with it. Put the result
6
431
  * in `incoming` of a fit to have it applied.
7
432
  */
8
- export function beacon(type_id: number): any;
433
+ export function beacon(type_id: number): Projection;
9
434
 
10
435
  /**
11
- * `js_options` may be left out; it then uses the defaults.
436
+ * `options` may be left out; it then uses the defaults.
12
437
  */
13
- export function calculate(js_fit: any, js_options: any): any;
14
-
15
- export function init(): void;
438
+ export function calculate(fit: Fit, options?: Options | null): Calculation;
16
439
 
17
440
  /**
18
441
  * Load a fit from EFT, the text format EVE copies a fit to the clipboard in.
19
442
  */
20
- export function load_eft(eft: string): any;
443
+ export function load_eft(eft: string): Fit;
21
444
 
22
445
  /**
23
446
  * Load `names.dat`, so an EFT written in another language than English also
@@ -32,8 +455,59 @@ export function load_names(bytes: Uint8Array): number;
32
455
  */
33
456
  export function load_sde(bytes: Uint8Array): number;
34
457
 
458
+ /**
459
+ * Write a fit as EFT, the text format EVE copies a fit to the clipboard in.
460
+ */
461
+ export function save_eft(fit: Fit): string;
462
+
463
+ export function set_panic_hook(): void;
464
+
35
465
  /**
36
466
  * Report the fitting rules the fit breaks. Calculates the fit itself, as
37
467
  * every rule reads the values after skills and modules changed them.
38
468
  */
39
- export function validate(js_fit: any): any;
469
+ export function validate(fit: Fit): Violation[];
470
+
471
+ export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;
472
+
473
+ export interface InitOutput {
474
+ readonly memory: WebAssembly.Memory;
475
+ readonly beacon: (a: number) => [number, number, number];
476
+ readonly calculate: (a: any, b: number) => [number, number, number];
477
+ readonly load_eft: (a: number, b: number) => [number, number, number];
478
+ readonly load_names: (a: number, b: number) => [number, number, number];
479
+ readonly load_sde: (a: number, b: number) => [number, number, number];
480
+ readonly save_eft: (a: any) => [number, number, number, number];
481
+ readonly set_panic_hook: () => void;
482
+ readonly validate: (a: any) => [number, number, number];
483
+ readonly __wbindgen_malloc: (a: number, b: number) => number;
484
+ readonly __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
485
+ readonly __wbindgen_exn_store: (a: number) => void;
486
+ readonly __externref_table_alloc: () => number;
487
+ readonly __wbindgen_externrefs: WebAssembly.Table;
488
+ readonly __wbindgen_free: (a: number, b: number, c: number) => void;
489
+ readonly __externref_table_dealloc: (a: number) => void;
490
+ readonly __wbindgen_start: () => void;
491
+ }
492
+
493
+ export type SyncInitInput = BufferSource | WebAssembly.Module;
494
+
495
+ /**
496
+ * Instantiates the given `module`, which can either be bytes or
497
+ * a precompiled `WebAssembly.Module`.
498
+ *
499
+ * @param {{ module: SyncInitInput }} module - Passing `SyncInitInput` directly is deprecated.
500
+ *
501
+ * @returns {InitOutput}
502
+ */
503
+ export function initSync(module: { module: SyncInitInput } | SyncInitInput): InitOutput;
504
+
505
+ /**
506
+ * If `module_or_path` is {RequestInfo} or {URL}, makes a request and
507
+ * for everything else, calls `WebAssembly.instantiate` directly.
508
+ *
509
+ * @param {{ module_or_path: InitInput | Promise<InitInput> }} module_or_path - Passing `InitInput` directly is deprecated.
510
+ *
511
+ * @returns {Promise<InitOutput>}
512
+ */
513
+ export default function __wbg_init (module_or_path?: { module_or_path: InitInput | Promise<InitInput> } | InitInput | Promise<InitInput>): Promise<InitOutput>;