@slot-engine/core 0.1.3 → 0.1.4
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/dist/index.d.mts +3 -4
- package/dist/index.d.ts +3 -4
- package/dist/index.js +173 -85
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +173 -85
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -34,6 +34,7 @@ import fs2 from "fs";
|
|
|
34
34
|
import path from "path";
|
|
35
35
|
import assert6 from "assert";
|
|
36
36
|
import zlib from "zlib";
|
|
37
|
+
import readline2 from "readline";
|
|
37
38
|
import { buildSync } from "esbuild";
|
|
38
39
|
import { Worker, isMainThread, parentPort, workerData } from "worker_threads";
|
|
39
40
|
|
|
@@ -201,6 +202,7 @@ var RandomNumberGenerator = class {
|
|
|
201
202
|
|
|
202
203
|
// utils.ts
|
|
203
204
|
import fs from "fs";
|
|
205
|
+
import readline from "readline";
|
|
204
206
|
function createDirIfNotExists(dirPath) {
|
|
205
207
|
if (!fs.existsSync(dirPath)) {
|
|
206
208
|
fs.mkdirSync(dirPath, { recursive: true });
|
|
@@ -232,6 +234,29 @@ var JSONL = class {
|
|
|
232
234
|
static parse(jsonl) {
|
|
233
235
|
return jsonl.split("\n").filter((s) => s !== "").map((str) => JSON.parse(str));
|
|
234
236
|
}
|
|
237
|
+
static async convertToJson(inputPath, outputPath) {
|
|
238
|
+
const writeStream = fs.createWriteStream(outputPath, { encoding: "utf-8" });
|
|
239
|
+
writeStream.write("[\n");
|
|
240
|
+
const rl = readline.createInterface({
|
|
241
|
+
input: fs.createReadStream(inputPath),
|
|
242
|
+
crlfDelay: Infinity
|
|
243
|
+
});
|
|
244
|
+
let isFirst = true;
|
|
245
|
+
for await (const line of rl) {
|
|
246
|
+
if (line.trim() === "") continue;
|
|
247
|
+
if (!isFirst) {
|
|
248
|
+
writeStream.write(",\n");
|
|
249
|
+
}
|
|
250
|
+
writeStream.write(line);
|
|
251
|
+
isFirst = false;
|
|
252
|
+
}
|
|
253
|
+
writeStream.write("\n]");
|
|
254
|
+
writeStream.end();
|
|
255
|
+
return new Promise((resolve, reject) => {
|
|
256
|
+
writeStream.on("finish", () => resolve());
|
|
257
|
+
writeStream.on("error", reject);
|
|
258
|
+
});
|
|
259
|
+
}
|
|
235
260
|
};
|
|
236
261
|
|
|
237
262
|
// src/result-set/index.ts
|
|
@@ -1412,8 +1437,10 @@ var Wallet = class {
|
|
|
1412
1437
|
};
|
|
1413
1438
|
|
|
1414
1439
|
// src/simulation/index.ts
|
|
1440
|
+
import { pipeline } from "stream/promises";
|
|
1415
1441
|
var completedSimulations = 0;
|
|
1416
1442
|
var TEMP_FILENAME = "__temp_compiled_src_IGNORE.js";
|
|
1443
|
+
var TEMP_FOLDER = "temp_files";
|
|
1417
1444
|
var Simulation = class {
|
|
1418
1445
|
gameConfigOpts;
|
|
1419
1446
|
gameConfig;
|
|
@@ -1422,15 +1449,15 @@ var Simulation = class {
|
|
|
1422
1449
|
debug = false;
|
|
1423
1450
|
actualSims = 0;
|
|
1424
1451
|
library;
|
|
1425
|
-
recorder;
|
|
1426
1452
|
wallet;
|
|
1453
|
+
recordsWriteStream;
|
|
1454
|
+
hasWrittenRecord = false;
|
|
1427
1455
|
constructor(opts, gameConfigOpts) {
|
|
1428
1456
|
this.gameConfig = createGameConfig(gameConfigOpts);
|
|
1429
1457
|
this.gameConfigOpts = gameConfigOpts;
|
|
1430
1458
|
this.simRunsAmount = opts.simRunsAmount || {};
|
|
1431
1459
|
this.concurrency = (opts.concurrency || 6) >= 2 ? opts.concurrency || 6 : 2;
|
|
1432
1460
|
this.library = /* @__PURE__ */ new Map();
|
|
1433
|
-
this.recorder = new Recorder();
|
|
1434
1461
|
this.wallet = new Wallet();
|
|
1435
1462
|
const gameModeKeys = Object.keys(this.gameConfig.gameModes);
|
|
1436
1463
|
assert6(
|
|
@@ -1456,7 +1483,7 @@ var Simulation = class {
|
|
|
1456
1483
|
completedSimulations = 0;
|
|
1457
1484
|
this.wallet = new Wallet();
|
|
1458
1485
|
this.library = /* @__PURE__ */ new Map();
|
|
1459
|
-
this.
|
|
1486
|
+
this.hasWrittenRecord = false;
|
|
1460
1487
|
debugDetails[mode] = {};
|
|
1461
1488
|
console.log(`
|
|
1462
1489
|
Simulating game mode: ${mode}`);
|
|
@@ -1468,8 +1495,59 @@ Simulating game mode: ${mode}`);
|
|
|
1468
1495
|
`Tried to simulate game mode "${mode}", but it's not configured in the game config.`
|
|
1469
1496
|
);
|
|
1470
1497
|
}
|
|
1498
|
+
const booksPath = path.join(
|
|
1499
|
+
this.gameConfig.rootDir,
|
|
1500
|
+
this.gameConfig.outputDir,
|
|
1501
|
+
`books_${mode}.jsonl`
|
|
1502
|
+
);
|
|
1503
|
+
const tempRecordsPath = path.join(
|
|
1504
|
+
this.gameConfig.rootDir,
|
|
1505
|
+
this.gameConfig.outputDir,
|
|
1506
|
+
TEMP_FOLDER,
|
|
1507
|
+
`temp_records_${mode}.jsonl`
|
|
1508
|
+
);
|
|
1509
|
+
createDirIfNotExists(
|
|
1510
|
+
path.join(this.gameConfig.rootDir, this.gameConfig.outputDir)
|
|
1511
|
+
);
|
|
1512
|
+
createDirIfNotExists(
|
|
1513
|
+
path.join(this.gameConfig.rootDir, this.gameConfig.outputDir, TEMP_FOLDER)
|
|
1514
|
+
);
|
|
1515
|
+
this.recordsWriteStream = fs2.createWriteStream(tempRecordsPath);
|
|
1471
1516
|
const simNumsToCriteria = ResultSet.assignCriteriaToSimulations(this, mode);
|
|
1472
1517
|
await this.spawnWorkersForGameMode({ mode, simNumsToCriteria });
|
|
1518
|
+
const finalBookStream = fs2.createWriteStream(booksPath);
|
|
1519
|
+
const numSims = Object.keys(simNumsToCriteria).length;
|
|
1520
|
+
const chunks = this.getSimRangesForChunks(numSims, this.concurrency);
|
|
1521
|
+
let isFirstChunk = true;
|
|
1522
|
+
for (let i = 0; i < chunks.length; i++) {
|
|
1523
|
+
const tempBookPath = path.join(
|
|
1524
|
+
this.gameConfig.rootDir,
|
|
1525
|
+
this.gameConfig.outputDir,
|
|
1526
|
+
TEMP_FOLDER,
|
|
1527
|
+
`temp_books_${mode}_${i}.jsonl`
|
|
1528
|
+
);
|
|
1529
|
+
if (fs2.existsSync(tempBookPath)) {
|
|
1530
|
+
if (!isFirstChunk) {
|
|
1531
|
+
finalBookStream.write("\n");
|
|
1532
|
+
}
|
|
1533
|
+
const content = fs2.createReadStream(tempBookPath);
|
|
1534
|
+
for await (const chunk of content) {
|
|
1535
|
+
finalBookStream.write(chunk);
|
|
1536
|
+
}
|
|
1537
|
+
fs2.rmSync(tempBookPath);
|
|
1538
|
+
isFirstChunk = false;
|
|
1539
|
+
}
|
|
1540
|
+
}
|
|
1541
|
+
finalBookStream.end();
|
|
1542
|
+
await new Promise((resolve) => finalBookStream.on("finish", resolve));
|
|
1543
|
+
if (this.recordsWriteStream) {
|
|
1544
|
+
await new Promise((resolve) => {
|
|
1545
|
+
this.recordsWriteStream.end(() => {
|
|
1546
|
+
resolve();
|
|
1547
|
+
});
|
|
1548
|
+
});
|
|
1549
|
+
this.recordsWriteStream = void 0;
|
|
1550
|
+
}
|
|
1473
1551
|
createDirIfNotExists(
|
|
1474
1552
|
path.join(
|
|
1475
1553
|
this.gameConfig.rootDir,
|
|
@@ -1480,11 +1558,13 @@ Simulating game mode: ${mode}`);
|
|
|
1480
1558
|
createDirIfNotExists(
|
|
1481
1559
|
path.join(this.gameConfig.rootDir, this.gameConfig.outputDir, "publish_files")
|
|
1482
1560
|
);
|
|
1561
|
+
console.log(`Writing final files for game mode: ${mode} ...`);
|
|
1483
1562
|
this.writeLookupTableCSV(mode);
|
|
1484
1563
|
this.writeLookupTableSegmentedCSV(mode);
|
|
1485
1564
|
this.writeRecords(mode);
|
|
1486
1565
|
await this.writeBooksJson(mode);
|
|
1487
1566
|
this.writeIndexJson();
|
|
1567
|
+
console.log(`Mode ${mode} done!`);
|
|
1488
1568
|
debugDetails[mode].rtp = this.wallet.getCumulativeWins() / (runs * this.gameConfig.gameModes[mode].cost);
|
|
1489
1569
|
debugDetails[mode].wins = this.wallet.getCumulativeWins();
|
|
1490
1570
|
debugDetails[mode].winsPerSpinType = this.wallet.getCumulativeWinsPerSpinType();
|
|
@@ -1563,6 +1643,12 @@ Simulating game mode: ${mode}`);
|
|
|
1563
1643
|
index
|
|
1564
1644
|
}
|
|
1565
1645
|
});
|
|
1646
|
+
const tempBookPath = path.join(
|
|
1647
|
+
basePath,
|
|
1648
|
+
TEMP_FOLDER,
|
|
1649
|
+
`temp_books_${mode}_${index}.jsonl`
|
|
1650
|
+
);
|
|
1651
|
+
const bookStream = fs2.createWriteStream(tempBookPath);
|
|
1566
1652
|
worker.on("message", (msg) => {
|
|
1567
1653
|
if (msg.type === "log") {
|
|
1568
1654
|
} else if (msg.type === "complete") {
|
|
@@ -1571,9 +1657,23 @@ Simulating game mode: ${mode}`);
|
|
|
1571
1657
|
logArrowProgress(completedSimulations, totalSims);
|
|
1572
1658
|
}
|
|
1573
1659
|
const book = Book.fromSerialized(msg.book);
|
|
1660
|
+
const bookData = {
|
|
1661
|
+
id: book.id,
|
|
1662
|
+
payoutMultiplier: book.payout,
|
|
1663
|
+
events: book.events
|
|
1664
|
+
};
|
|
1665
|
+
const prefix = book.id === simStart ? "" : "\n";
|
|
1666
|
+
bookStream.write(prefix + JSONL.stringify([bookData]));
|
|
1667
|
+
book.events = [];
|
|
1574
1668
|
this.library.set(book.id, book);
|
|
1669
|
+
if (this.recordsWriteStream) {
|
|
1670
|
+
for (const record of msg.records) {
|
|
1671
|
+
const recordPrefix = this.hasWrittenRecord ? "\n" : "";
|
|
1672
|
+
this.recordsWriteStream.write(recordPrefix + JSONL.stringify([record]));
|
|
1673
|
+
this.hasWrittenRecord = true;
|
|
1674
|
+
}
|
|
1675
|
+
}
|
|
1575
1676
|
this.wallet.mergeSerialized(msg.wallet);
|
|
1576
|
-
this.mergeRecords(msg.records);
|
|
1577
1677
|
} else if (msg.type === "done") {
|
|
1578
1678
|
resolve(true);
|
|
1579
1679
|
}
|
|
@@ -1716,16 +1816,61 @@ Simulating game mode: ${mode}`);
|
|
|
1716
1816
|
writeFile(outputFilePath, rows.join("\n"));
|
|
1717
1817
|
return outputFilePath;
|
|
1718
1818
|
}
|
|
1719
|
-
writeRecords(
|
|
1720
|
-
const
|
|
1721
|
-
const outputFilePath = path.join(
|
|
1819
|
+
async writeRecords(mode) {
|
|
1820
|
+
const tempRecordsPath = path.join(
|
|
1722
1821
|
this.gameConfig.rootDir,
|
|
1723
1822
|
this.gameConfig.outputDir,
|
|
1724
|
-
|
|
1823
|
+
TEMP_FOLDER,
|
|
1824
|
+
`temp_records_${mode}.jsonl`
|
|
1725
1825
|
);
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1826
|
+
const forceRecordsPath = path.join(
|
|
1827
|
+
this.gameConfig.rootDir,
|
|
1828
|
+
this.gameConfig.outputDir,
|
|
1829
|
+
`force_record_${mode}.json`
|
|
1830
|
+
);
|
|
1831
|
+
const aggregatedRecords = /* @__PURE__ */ new Map();
|
|
1832
|
+
if (fs2.existsSync(tempRecordsPath)) {
|
|
1833
|
+
const fileStream = fs2.createReadStream(tempRecordsPath);
|
|
1834
|
+
const rl = readline2.createInterface({
|
|
1835
|
+
input: fileStream,
|
|
1836
|
+
crlfDelay: Infinity
|
|
1837
|
+
});
|
|
1838
|
+
for await (const line of rl) {
|
|
1839
|
+
if (line.trim() === "") continue;
|
|
1840
|
+
const record = JSON.parse(line);
|
|
1841
|
+
const key = JSON.stringify(record.search);
|
|
1842
|
+
let existing = aggregatedRecords.get(key);
|
|
1843
|
+
if (!existing) {
|
|
1844
|
+
existing = {
|
|
1845
|
+
search: record.search,
|
|
1846
|
+
timesTriggered: 0,
|
|
1847
|
+
bookIds: []
|
|
1848
|
+
};
|
|
1849
|
+
aggregatedRecords.set(key, existing);
|
|
1850
|
+
}
|
|
1851
|
+
existing.timesTriggered += record.timesTriggered;
|
|
1852
|
+
for (const bookId of record.bookIds) {
|
|
1853
|
+
existing.bookIds.push(bookId);
|
|
1854
|
+
}
|
|
1855
|
+
}
|
|
1856
|
+
}
|
|
1857
|
+
fs2.rmSync(forceRecordsPath, { force: true });
|
|
1858
|
+
const writeStream = fs2.createWriteStream(forceRecordsPath, { encoding: "utf-8" });
|
|
1859
|
+
writeStream.write("[\n");
|
|
1860
|
+
let isFirst = true;
|
|
1861
|
+
for (const record of aggregatedRecords.values()) {
|
|
1862
|
+
if (!isFirst) {
|
|
1863
|
+
writeStream.write(",\n");
|
|
1864
|
+
}
|
|
1865
|
+
writeStream.write(JSON.stringify(record));
|
|
1866
|
+
isFirst = false;
|
|
1867
|
+
}
|
|
1868
|
+
writeStream.write("\n]");
|
|
1869
|
+
writeStream.end();
|
|
1870
|
+
await new Promise((resolve) => {
|
|
1871
|
+
writeStream.on("finish", () => resolve());
|
|
1872
|
+
});
|
|
1873
|
+
fs2.rmSync(tempRecordsPath, { force: true });
|
|
1729
1874
|
}
|
|
1730
1875
|
writeIndexJson() {
|
|
1731
1876
|
const outputFilePath = path.join(
|
|
@@ -1747,54 +1892,25 @@ Simulating game mode: ${mode}`);
|
|
|
1747
1892
|
writeFile(outputFilePath, JSON.stringify({ modes }, null, 2));
|
|
1748
1893
|
}
|
|
1749
1894
|
async writeBooksJson(gameMode) {
|
|
1750
|
-
const outputFileName = `books_${gameMode}.jsonl`;
|
|
1751
1895
|
const outputFilePath = path.join(
|
|
1752
1896
|
this.gameConfig.rootDir,
|
|
1753
1897
|
this.gameConfig.outputDir,
|
|
1754
|
-
|
|
1898
|
+
`books_${gameMode}.jsonl`
|
|
1755
1899
|
);
|
|
1756
|
-
const books = Array.from(this.library.values()).map((b) => b.serialize()).map((b) => ({
|
|
1757
|
-
id: b.id,
|
|
1758
|
-
payoutMultiplier: b.payout,
|
|
1759
|
-
events: b.events
|
|
1760
|
-
})).sort((a, b) => a.id - b.id);
|
|
1761
|
-
const contents = JSONL.stringify(books);
|
|
1762
|
-
writeFile(outputFilePath, contents);
|
|
1763
|
-
const compressedFileName = `books_${gameMode}.jsonl.zst`;
|
|
1764
1900
|
const compressedFilePath = path.join(
|
|
1765
1901
|
this.gameConfig.rootDir,
|
|
1766
1902
|
this.gameConfig.outputDir,
|
|
1767
1903
|
"publish_files",
|
|
1768
|
-
|
|
1904
|
+
`books_${gameMode}.jsonl.zst`
|
|
1769
1905
|
);
|
|
1770
1906
|
fs2.rmSync(compressedFilePath, { force: true });
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
const structuredRecords = validRecords.map((r) => {
|
|
1779
|
-
const symbolEntry = r.search.find((s) => s.name === "symbolId");
|
|
1780
|
-
const kindEntry = r.search.find((s) => s.name === "kind");
|
|
1781
|
-
const spinTypeEntry = r.search.find((s) => s.name === "spinType");
|
|
1782
|
-
return {
|
|
1783
|
-
symbol: symbolEntry ? symbolEntry.value : "unknown",
|
|
1784
|
-
kind: kindEntry ? kindEntry.value : "unknown",
|
|
1785
|
-
spinType: spinTypeEntry ? spinTypeEntry.value : "unknown",
|
|
1786
|
-
timesTriggered: r.timesTriggered
|
|
1787
|
-
};
|
|
1788
|
-
}).sort((a, b) => {
|
|
1789
|
-
if (a.symbol < b.symbol) return -1;
|
|
1790
|
-
if (a.symbol > b.symbol) return 1;
|
|
1791
|
-
if (a.kind < b.kind) return -1;
|
|
1792
|
-
if (a.kind > b.kind) return 1;
|
|
1793
|
-
if (a.spinType < b.spinType) return -1;
|
|
1794
|
-
if (a.spinType > b.spinType) return 1;
|
|
1795
|
-
return 0;
|
|
1796
|
-
});
|
|
1797
|
-
console.table(structuredRecords);
|
|
1907
|
+
if (fs2.existsSync(outputFilePath)) {
|
|
1908
|
+
await pipeline(
|
|
1909
|
+
fs2.createReadStream(outputFilePath),
|
|
1910
|
+
zlib.createZstdCompress(),
|
|
1911
|
+
fs2.createWriteStream(compressedFilePath)
|
|
1912
|
+
);
|
|
1913
|
+
}
|
|
1798
1914
|
}
|
|
1799
1915
|
/**
|
|
1800
1916
|
* Compiles user configured game to JS for use in different Node processes
|
|
@@ -1832,32 +1948,6 @@ Simulating game mode: ${mode}`);
|
|
|
1832
1948
|
}
|
|
1833
1949
|
return result;
|
|
1834
1950
|
}
|
|
1835
|
-
mergeRecords(otherRecords) {
|
|
1836
|
-
for (const otherRecord of otherRecords) {
|
|
1837
|
-
let record = this.recorder.records.find((r) => {
|
|
1838
|
-
if (r.search.length !== otherRecord.search.length) return false;
|
|
1839
|
-
for (let i = 0; i < r.search.length; i++) {
|
|
1840
|
-
if (r.search[i].name !== otherRecord.search[i].name) return false;
|
|
1841
|
-
if (r.search[i].value !== otherRecord.search[i].value) return false;
|
|
1842
|
-
}
|
|
1843
|
-
return true;
|
|
1844
|
-
});
|
|
1845
|
-
if (!record) {
|
|
1846
|
-
record = {
|
|
1847
|
-
search: otherRecord.search,
|
|
1848
|
-
timesTriggered: 0,
|
|
1849
|
-
bookIds: []
|
|
1850
|
-
};
|
|
1851
|
-
this.recorder.records.push(record);
|
|
1852
|
-
}
|
|
1853
|
-
record.timesTriggered += otherRecord.timesTriggered;
|
|
1854
|
-
for (const bookId of otherRecord.bookIds) {
|
|
1855
|
-
if (!record.bookIds.includes(bookId)) {
|
|
1856
|
-
record.bookIds.push(bookId);
|
|
1857
|
-
}
|
|
1858
|
-
}
|
|
1859
|
-
}
|
|
1860
|
-
}
|
|
1861
1951
|
/**
|
|
1862
1952
|
* Generates reelset CSV files for all game modes.
|
|
1863
1953
|
*/
|
|
@@ -2471,11 +2561,6 @@ var Optimizer = class {
|
|
|
2471
2561
|
);
|
|
2472
2562
|
}
|
|
2473
2563
|
}
|
|
2474
|
-
const criteria = configMode.resultSets.map((r) => r.criteria);
|
|
2475
|
-
assert9(
|
|
2476
|
-
conditions.every((c) => criteria.includes(c)),
|
|
2477
|
-
`Not all ResultSet criteria in game mode "${k}" are defined as optimization conditions.`
|
|
2478
|
-
);
|
|
2479
2564
|
let gameModeRtp = configMode.rtp;
|
|
2480
2565
|
let paramRtp = 0;
|
|
2481
2566
|
for (const cond of conditions) {
|
|
@@ -2528,6 +2613,7 @@ async function rustProgram(...args) {
|
|
|
2528
2613
|
}
|
|
2529
2614
|
|
|
2530
2615
|
// src/slot-game/index.ts
|
|
2616
|
+
import { isMainThread as isMainThread4 } from "worker_threads";
|
|
2531
2617
|
var SlotGame = class {
|
|
2532
2618
|
configOpts;
|
|
2533
2619
|
simulation;
|
|
@@ -2603,6 +2689,7 @@ var SlotGame = class {
|
|
|
2603
2689
|
if (opts.doAnalysis) {
|
|
2604
2690
|
await this.runAnalysis(opts.analysisOpts || { gameModes: [] });
|
|
2605
2691
|
}
|
|
2692
|
+
if (isMainThread4) console.log("Finishing up...");
|
|
2606
2693
|
}
|
|
2607
2694
|
/**
|
|
2608
2695
|
* Gets the game configuration.
|
|
@@ -2884,13 +2971,14 @@ var ClusterWinType = class extends WinType {
|
|
|
2884
2971
|
}
|
|
2885
2972
|
}
|
|
2886
2973
|
}
|
|
2887
|
-
|
|
2974
|
+
for (const cluster of potentialClusters) {
|
|
2888
2975
|
const kind = cluster.length;
|
|
2889
2976
|
let baseSymbol = cluster.find((s) => !this.isWild(s.symbol))?.symbol;
|
|
2890
2977
|
if (!baseSymbol) baseSymbol = cluster[0].symbol;
|
|
2891
2978
|
const payout = this.getSymbolPayout(baseSymbol, kind);
|
|
2979
|
+
if (payout === 0) continue;
|
|
2892
2980
|
if (!baseSymbol.pays || Object.keys(baseSymbol.pays).length === 0) {
|
|
2893
|
-
|
|
2981
|
+
continue;
|
|
2894
2982
|
}
|
|
2895
2983
|
clusterWins.push({
|
|
2896
2984
|
payout,
|
|
@@ -2903,7 +2991,7 @@ var ClusterWinType = class extends WinType {
|
|
|
2903
2991
|
posIndex: s.row
|
|
2904
2992
|
}))
|
|
2905
2993
|
});
|
|
2906
|
-
}
|
|
2994
|
+
}
|
|
2907
2995
|
for (const win of clusterWins) {
|
|
2908
2996
|
this.ctx.services.data.recordSymbolOccurrence({
|
|
2909
2997
|
kind: win.kind,
|
|
@@ -3068,7 +3156,7 @@ var ManywaysWinType = class extends WinType {
|
|
|
3068
3156
|
// src/reel-set/GeneratedReelSet.ts
|
|
3069
3157
|
import fs5 from "fs";
|
|
3070
3158
|
import path7 from "path";
|
|
3071
|
-
import { isMainThread as
|
|
3159
|
+
import { isMainThread as isMainThread5 } from "worker_threads";
|
|
3072
3160
|
|
|
3073
3161
|
// src/reel-set/index.ts
|
|
3074
3162
|
import fs4 from "fs";
|
|
@@ -3413,7 +3501,7 @@ var GeneratedReelSet = class extends ReelSet {
|
|
|
3413
3501
|
}
|
|
3414
3502
|
}
|
|
3415
3503
|
const csvString = csvRows.map((row) => row.join(",")).join("\n");
|
|
3416
|
-
if (
|
|
3504
|
+
if (isMainThread5) {
|
|
3417
3505
|
fs5.writeFileSync(filePath, csvString);
|
|
3418
3506
|
this.reels = this.parseReelsetCSV(filePath, config);
|
|
3419
3507
|
console.log(
|