@eveshipfit/dogma-engine 10.3.0 → 11.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
@@ -2,6 +2,7 @@
2
2
 
3
3
  [![crates.io](https://img.shields.io/crates/v/esf-dogma-engine.svg)](https://crates.io/crates/esf-dogma-engine)
4
4
  [![npm](https://img.shields.io/npm/v/%40eveshipfit%2Fdogma-engine.svg)](https://www.npmjs.com/package/@eveshipfit/dogma-engine)
5
+ [![PyPI](https://img.shields.io/pypi/v/eveshipfit-dogma-engine.svg)](https://pypi.org/project/eveshipfit-dogma-engine/)
5
6
  [![CI](https://github.com/EVEShipFit/dogma-engine/actions/workflows/testing.yml/badge.svg)](https://github.com/EVEShipFit/dogma-engine/actions/workflows/testing.yml)
6
7
  [![docs.rs](https://img.shields.io/docsrs/esf-dogma-engine)](https://docs.rs/esf-dogma-engine)
7
8
 
@@ -36,15 +37,38 @@ All identifiers are those from the SDE.
36
37
  - `items`: everything fitted or carried. Each item has:
37
38
  - `type_id`: its type.
38
39
  - `slot`: where the item is.
39
- - `type`: `high`, `medium`, `low`, `rig`, `subsystem`, `service`, `fighter_tube`, `fighter_bay`, `drone_bay` or `cargo`.
40
- _`cargo` is carried, but not calculated._
41
- - `index`: position within that slot type, starting at 0. Absent for `fighter_bay`, `drone_bay` and `cargo`.
40
+ - `type`: `high`, `medium`, `low`, `rig`, `subsystem`, `service`, `fighter_tube`, `fighter_bay`, `implant`, `booster`, `drone_bay` or `cargo`.
41
+ - `index`: position within that slot type, starting at 0 (`implant` and `booster` starting at 1).
42
+ Absent for `fighter_bay`, `drone_bay` and `cargo`.
42
43
  - `quantity` (optional, default 1): stack size for drones, fighters and cargo. For fighters in a tube, the squadron size.
43
44
  - `state`: requested state; `offline`, `online`, `active` or `overload`.
44
45
  - `charge` (optional): the loaded charge, as `type_id`.
46
+ - `mutation` (optional): for mutated items (Abyssal modules, mutated drones, ...).
47
+ - `base`: type ID of the item before it was mutated.
48
+ - `attributes`: the rolled value per attribute ID.
45
49
  - `fighter_abilities` (optional): the abilities a fighter uses, as effect IDs. Absent means the fighter's default abilities.
50
+ - `booster_side_effects` (optional): the side effects a booster rolled, as effect IDs. Absent means none.
51
+ - `spool` (optional): for modules whose bonus grows every cycle, how far it has spooled.
52
+ Only per-second stats use it; volley is always unspooled. Absent means fully spooled.
53
+ - `multiplier_bonus`: the bonus reached so far; 0.0 is unspooled, 2.125 is +212.5%.
46
54
  - `character` (optional):
47
55
  - `skills`: level (0 to 5) per skill type ID. A missing skill gives no bonuses.
56
+ - `security_status` (optional, default 0.0): the pilot's security status, -10.0 to 5.0.
57
+ - `environment` (optional): where the fit is.
58
+ - `damage_profile` (optional, default 0.25 each): incoming damage for effective hitpoints, as `em`, `explosive`, `kinetic` and `thermal` (relative to each other).
59
+ - `security` (optional, default `high_sec`): `high_sec`, `low_sec`, `null_sec` or `wormhole`.
60
+ - `reactive_armor` (optional, default `do_not_adapt`): what a Reactive Armor Hardener shifts its resistances towards.
61
+ `do_not_adapt` leaves them where EVE shows them, `damage_profile` shifts towards `damage_profile`, and
62
+ `{"profile": {..}}` shifts towards a profile of its own, written the same way as `damage_profile`.
63
+ - `incoming` (optional): what effects and buffs to apply that come from outside the ship.
64
+ A calculation reports the same shape as `outgoing`: feed one fit's result into another's `incoming` links them up.
65
+ - `buffs` (optional, default none): buffs to apply, like the ones a command burst hands out.
66
+ - `id`: which buff, as `dbuffCollections` in the SDE numbers them.
67
+ - `value`: how strong it is, in whatever the buff's operation reads.
68
+ - `effects` (optional, default none): effects aimed at the fit, like a stasis webifier.
69
+ - `type_id`: the type the effect belongs to; its category decides the stacking penalty.
70
+ - `effect_id`: which effect, as `dogmaEffects` in the SDE numbers them.
71
+ - `attributes`: the value per attribute ID the effect reads, worked out by the fit that aimed it.
48
72
 
49
73
  ### Options
50
74
 
@@ -57,16 +81,20 @@ All identifiers are those from the SDE.
57
81
  - `mode`: result for the mode; absent when the fit has no mode.
58
82
  - `items`: one result per item of the fit, in the same order.
59
83
  - `character`: result for the character.
84
+ - `buffs`: the buffs that landed, ordered by id. Those of `incoming`, plus the ones the fit's own bursts hand out: a fleet boost reaches the ship running it. What is missing lost to another source of the same buff, or the SDE has no such buff.
85
+ - `id`: which buff, as `dbuffCollections` in the SDE numbers them.
86
+ - `value`: how strong it is, in whatever the buff's operation reads.
87
+ - `outgoing`: what the fit hands to other fits, in the shape `incoming` takes.
60
88
 
61
89
  Each result has:
62
90
 
63
91
  - `attributes`: per attribute ID, its `base` value before effects and its final `value`.
64
92
  With the `sources` option, also `sources`: every modifier on it, in the order they were applied. Each has:
65
- - `from`: where it comes from; `type` is `ship`, `mode`, `character`, `item` or `charge` (with the `index` into `items`), or `skill` (with its `type_id`).
66
- - `effect_id`: the effect that modifies.
67
- - `source_attribute_id`: the attribute on the source that holds `value`.
93
+ - `from`: where it comes from; `type` is `ship`, `mode`, `character`, `item` or `charge` (with the `index` into `items`), `projected` (with the `index` into `incoming.effects`), `skill` (with its `type_id`) or `buff` (with its `id`).
94
+ - `effect_id`: the effect that holds the modifier; `null` for a buff, which has none.
95
+ - `source_attribute_id`: the attribute on the source that holds `value`; `null` for a buff, which carries its own strength.
68
96
  - `operator`: `pre_assign`, `pre_mul`, `pre_div`, `mod_add`, `mod_sub`, `post_mul`, `post_div`, `post_percent` or `post_assign`.
69
- - `value`: the value of the modifying attribute.
97
+ - `value`: the value of the modifying attribute, or the strength of the buff.
70
98
  - `quantity`: how many times it counts. A stacking penalised stack is listed once per item instead.
71
99
  - `penalty`: the stacking penalty factor it got, or `null` if not penalised.
72
100
  - `applied`: false when the source's state is too low for the effect.
@@ -84,6 +112,128 @@ To make rendering a fit easier, these are calculated by this library, and presen
84
112
  Their identifier is always a negative value, to visually separate them.
85
113
  What additional attributes exist are defined in [EVEShipFit/sde-patched](https://github.com/EVEShipFit/sde-patched) repository.
86
114
 
115
+ ## Usage
116
+
117
+ The engine is published for Rust, Javascript and Python; all three calculate the same way.
118
+ Each hands over `sde.dat` once, and every lookup after that happens inside Rust.
119
+ An EFT import matches the English names in `sde.dat`; hand over `names.dat` too to also match the other languages EVE supports.
120
+
121
+ How each package is built is explained under [Integration](#integration).
122
+
123
+ ### Rust
124
+
125
+ The crate is published on crates.io as [`esf-dogma-engine`](https://crates.io/crates/esf-dogma-engine).
126
+ `esf-data` reads `sde.dat`.
127
+
128
+ ```bash
129
+ cargo add esf-dogma-engine esf-data
130
+ ```
131
+
132
+ ```rust
133
+ use esf_data::{InfoSde, Sde};
134
+ use esf_dogma_engine::{Fit, Options, beacon, calculate};
135
+
136
+ let bytes = std::fs::read("sde.dat")?;
137
+ let sde = Sde::new(&bytes)?;
138
+ let info = InfoSde::new(&sde);
139
+
140
+ let fit: Fit = serde_json::from_str(
141
+ r#"{
142
+ "ship": {"type_id": 587},
143
+ "items": [
144
+ {
145
+ "type_id": 2873,
146
+ "slot": {"type": "high", "index": 0},
147
+ "state": "active",
148
+ "charge": {"type_id": 185}
149
+ }
150
+ ],
151
+ "character": {"skills": {"3300": 5}}
152
+ }"#,
153
+ )?;
154
+
155
+ let calculation = calculate(&info, &fit, &Options::default());
156
+ // Or if you want to know the source of the effects:
157
+ let with_sources = calculate(&info, &fit, &Options { sources: true, ..Default::default() });
158
+ // Or if you have a beacon in space (like wormhole effects):
159
+ let with_beacon = calculate(&info, &Fit { incoming: beacon(&info, beacon_type_id), ..fit }, &Options::default());
160
+ ```
161
+
162
+ ### Javascript (WebAssembly)
163
+
164
+ The WebAssembly variant is published on npm as
165
+ [`@eveshipfit/dogma-engine`](https://www.npmjs.com/package/@eveshipfit/dogma-engine).
166
+ [`@eveshipfit/sde`](https://www.npmjs.com/package/@eveshipfit/sde) ships `sde.dat` in its `dist` folder; serve or bundle that file.
167
+
168
+ ```bash
169
+ npm install @eveshipfit/dogma-engine @eveshipfit/sde
170
+ ```
171
+
172
+ ```js
173
+ import init, { init as initPanicHook, load_sde, load_eft, calculate, beacon } from "@eveshipfit/dogma-engine";
174
+
175
+ await init();
176
+ initPanicHook();
177
+
178
+ const sde = await fetch("/sde.dat").then((response) => response.arrayBuffer());
179
+ const buildNumber = load_sde(new Uint8Array(sde));
180
+ const fit = {
181
+ ship: { type_id: 587 },
182
+ items: [{ type_id: 2873, slot: { type: "high", index: 0 }, state: "active", charge: { type_id: 185 } }],
183
+ character: { skills: { 3300: 5 } },
184
+ };
185
+
186
+ const calculation = calculate(fit);
187
+ /* Or if you want to know the source of the effects: */
188
+ const withSources = calculate(fit, { sources: true });
189
+ /* Or if you have a beacon in space (like wormhole effects): */
190
+ const withBeacon = calculate({ ...fit, incoming: beacon(beaconTypeId) });
191
+ /* Or if you have an EFT, the text format EVE copies a fit to the clipboard in: */
192
+ const imported = calculate(load_eft("[Rifter, My Rifter]\n200mm AutoCannon I"));
193
+ ```
194
+
195
+ ### Python
196
+
197
+ The Python variant is published on PyPI as
198
+ [`eveshipfit-dogma-engine`](https://pypi.org/project/eveshipfit-dogma-engine/).
199
+ The `sde` extra brings in [`eveshipfit-sde`](https://pypi.org/project/eveshipfit-sde/), which ships `sde.dat`.
200
+
201
+ ```bash
202
+ pip install eveshipfit-dogma-engine[sde]
203
+ ```
204
+
205
+ ```python
206
+ import esf_dogma_engine as dogma
207
+ from eveshipfit_sde import sde_path
208
+
209
+ build_number = dogma.load_sde_from_file(sde_path())
210
+
211
+ fit = {
212
+ "ship": {"type_id": 587},
213
+ "items": [
214
+ {
215
+ "type_id": 2873,
216
+ "slot": {"type": "high", "index": 0},
217
+ "state": "active",
218
+ "charge": {"type_id": 185},
219
+ }
220
+ ],
221
+ "character": {"skills": {3300: 5}},
222
+ }
223
+
224
+ calculation = dogma.calculate(fit)
225
+ # Or if you want to know the source of the effects:
226
+ with_sources = dogma.calculate(fit, {"sources": True})
227
+ # Or if you have a beacon in space (like wormhole effects):
228
+ with_beacon = dogma.calculate({**fit, "incoming": dogma.beacon(beacon_type_id)})
229
+ # Or if you have an EFT, the text format EVE copies a fit to the clipboard in:
230
+ imported = dogma.calculate(dogma.load_eft("[Rifter, My Rifter]\n200mm AutoCannon I"))
231
+ ```
232
+
233
+ Fits and calculations are plain dicts, typed with `TypedDict` in `esf_dogma_engine.types`.
234
+
235
+ `load_eft`, `calculate` and `beacon` release the GIL while they work, so a thread pool calculates fits in parallel.
236
+
87
237
  ## Development
88
238
 
89
239
  Make sure you have [Rust installed](https://www.rust-lang.org/tools/install).
@@ -108,6 +258,15 @@ flatc --rust --gen-onefile -o crates/esf-data/src/sde/ node_modules/@eveshipfit/
108
258
  cargo run --release -p esf-cli
109
259
  ```
110
260
 
261
+ For example, some attributes of a fit with every skill at L0 except two:
262
+
263
+ ```bash
264
+ printf '[Nergal, Spool]\nLight Entropic Disintegrator II, Occult S\n' \
265
+ | cargo run --release -p esf-cli -- -l 0 --skill "Gunnery=4" --skill "Rapid Firing=2" -a damage -a speed
266
+ ```
267
+
268
+ It prints a table on a terminal and JSON otherwise; see `--help` for the rest.
269
+
111
270
  The regression suite reads the same paths; set `ESF_SDE` and `ESF_NAMES` to point it elsewhere.
112
271
 
113
272
  ## Regression
@@ -128,6 +287,16 @@ cargo insta review
128
287
 
129
288
  ## Integration
130
289
 
290
+ Every variant is built from the same Rust crates; the `flatc` step from [Development](#development) comes first.
291
+
292
+ ### Rust
293
+
294
+ The engine itself is a plain crate; [`esf-cli`](./crates/esf-cli) is an example of using it.
295
+
296
+ ```bash
297
+ cargo build --release -p esf-dogma-engine
298
+ ```
299
+
131
300
  ### Javascript (WebAssembly)
132
301
 
133
302
  The primary goal of this library is to build a WebAssembly variant that can easily be used in the browser.
@@ -142,24 +311,13 @@ wasm-pack build crates/esf-wasm --release --out-dir ../../pkg
142
311
 
143
312
  In the `pkg` folder is now a NPM module to use.
144
313
 
145
- Javascript hands over `sde.dat` once, and every lookup after that happens inside WebAssembly.
146
- The file is a Flatbuffer, so nothing is parsed: the bytes are used where they land.
314
+ ### Python
147
315
 
148
- ```js
149
- import init, { init as initPanicHook, load_sde, calculate } from "@eveshipfit/dogma-engine";
316
+ This is done with [maturin](https://www.maturin.rs/):
150
317
 
151
- await init();
152
- initPanicHook();
153
-
154
- const sde = await fetch("/sde.dat").then((response) => response.arrayBuffer());
155
- const buildNumber = load_sde(new Uint8Array(sde));
156
- const fit = {
157
- ship: { type_id: 587 },
158
- items: [{ type_id: 2873, slot: { type: "high", index: 0 }, state: "active", charge: { type_id: 185 } }],
159
- character: { skills: { 3300: 5 } },
160
- };
161
-
162
- const calculation = calculate(fit);
163
- /* Or if you want to know the source of the effects: */
164
- const withSources = calculate(fit, { sources: true });
318
+ ```bash
319
+ cargo install maturin
320
+ maturin build --release
165
321
  ```
322
+
323
+ In the `target/wheels` folder is now a wheel to install.
@@ -1,6 +1,12 @@
1
1
  /* tslint:disable */
2
2
  /* eslint-disable */
3
3
 
4
+ /**
5
+ * What a beacon in space hands to every fit in there with it. Put the result
6
+ * in `incoming` of a fit to have it applied.
7
+ */
8
+ export function beacon(type_id: number): any;
9
+
4
10
  /**
5
11
  * `js_options` may be left out; it then uses the defaults.
6
12
  */
@@ -8,6 +14,18 @@ export function calculate(js_fit: any, js_options: any): any;
8
14
 
9
15
  export function init(): void;
10
16
 
17
+ /**
18
+ * Load a fit from EFT, the text format EVE copies a fit to the clipboard in.
19
+ */
20
+ export function load_eft(eft: string): any;
21
+
22
+ /**
23
+ * Load `names.dat`, so an EFT written in another language than English also
24
+ * imports. Optional; without it only English names match. Has to be called
25
+ * after `load_sde`, and calling it twice is an error.
26
+ */
27
+ export function load_names(bytes: Uint8Array): number;
28
+
11
29
  /**
12
30
  * Load `sde.dat`. Has to be called before `calculate`; calling it twice is an
13
31
  * error, as the first buffer is borrowed for the rest of the session.
@@ -5,5 +5,5 @@ import { __wbg_set_wasm } from "./esf_dogma_engine_bg.js";
5
5
  __wbg_set_wasm(wasm);
6
6
  wasm.__wbindgen_start();
7
7
  export {
8
- calculate, init, load_sde
8
+ beacon, calculate, init, load_eft, load_names, load_sde
9
9
  } from "./esf_dogma_engine_bg.js";
@@ -1,3 +1,17 @@
1
+ /**
2
+ * What a beacon in space hands to every fit in there with it. Put the result
3
+ * in `incoming` of a fit to have it applied.
4
+ * @param {number} type_id
5
+ * @returns {any}
6
+ */
7
+ export function beacon(type_id) {
8
+ const ret = wasm.beacon(type_id);
9
+ if (ret[2]) {
10
+ throw takeFromExternrefTable0(ret[1]);
11
+ }
12
+ return takeFromExternrefTable0(ret[0]);
13
+ }
14
+
1
15
  /**
2
16
  * `js_options` may be left out; it then uses the defaults.
3
17
  * @param {any} js_fit
@@ -16,6 +30,38 @@ export function init() {
16
30
  wasm.init();
17
31
  }
18
32
 
33
+ /**
34
+ * Load a fit from EFT, the text format EVE copies a fit to the clipboard in.
35
+ * @param {string} eft
36
+ * @returns {any}
37
+ */
38
+ export function load_eft(eft) {
39
+ const ptr0 = passStringToWasm0(eft, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
40
+ const len0 = WASM_VECTOR_LEN;
41
+ const ret = wasm.load_eft(ptr0, len0);
42
+ if (ret[2]) {
43
+ throw takeFromExternrefTable0(ret[1]);
44
+ }
45
+ return takeFromExternrefTable0(ret[0]);
46
+ }
47
+
48
+ /**
49
+ * Load `names.dat`, so an EFT written in another language than English also
50
+ * imports. Optional; without it only English names match. Has to be called
51
+ * after `load_sde`, and calling it twice is an error.
52
+ * @param {Uint8Array} bytes
53
+ * @returns {number}
54
+ */
55
+ export function load_names(bytes) {
56
+ const ptr0 = passArray8ToWasm0(bytes, wasm.__wbindgen_malloc);
57
+ const len0 = WASM_VECTOR_LEN;
58
+ const ret = wasm.load_names(ptr0, len0);
59
+ if (ret[2]) {
60
+ throw takeFromExternrefTable0(ret[1]);
61
+ }
62
+ return ret[0];
63
+ }
64
+
19
65
  /**
20
66
  * Load `sde.dat`. Has to be called before `calculate`; calling it twice is an
21
67
  * error, as the first buffer is borrowed for the rest of the session.
Binary file
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "EVEShipFit Team <info@eveship.fit>"
6
6
  ],
7
7
  "description": "Library to calculate statistics for EVE Online ship fits",
8
- "version": "10.3.0",
8
+ "version": "11.0.0",
9
9
  "license": "MIT",
10
10
  "repository": {
11
11
  "type": "git",