@slot-engine/core 0.2.10 → 0.2.12

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 CHANGED
@@ -65,6 +65,7 @@ type PermanentFilePaths = {
65
65
  statsPayouts: string;
66
66
  statsSummary: string;
67
67
  statsRecords: string;
68
+ frontendConfig: string;
68
69
  };
69
70
  type TemporaryFilePaths = {
70
71
  tempBooks: (mode: string, i: number) => string;
@@ -723,17 +724,6 @@ declare class Book {
723
724
  * Adds an event to the book.
724
725
  */
725
726
  addEvent(event: Omit<BookEvent, "index">): void;
726
- /**
727
- * Intended for internal use only.
728
- */
729
- _serialize(): {
730
- id: number;
731
- criteria: string;
732
- events: BookEvent[];
733
- payout: number;
734
- basegameWins: number;
735
- freespinsWins: number;
736
- };
737
727
  }
738
728
  interface BookEvent {
739
729
  index: number;
package/dist/index.d.ts CHANGED
@@ -65,6 +65,7 @@ type PermanentFilePaths = {
65
65
  statsPayouts: string;
66
66
  statsSummary: string;
67
67
  statsRecords: string;
68
+ frontendConfig: string;
68
69
  };
69
70
  type TemporaryFilePaths = {
70
71
  tempBooks: (mode: string, i: number) => string;
@@ -723,17 +724,6 @@ declare class Book {
723
724
  * Adds an event to the book.
724
725
  */
725
726
  addEvent(event: Omit<BookEvent, "index">): void;
726
- /**
727
- * Intended for internal use only.
728
- */
729
- _serialize(): {
730
- id: number;
731
- criteria: string;
732
- events: BookEvent[];
733
- payout: number;
734
- basegameWins: number;
735
- freespinsWins: number;
736
- };
737
727
  }
738
728
  interface BookEvent {
739
729
  index: number;
package/dist/index.js CHANGED
@@ -94,7 +94,8 @@ function createPermanentFilePaths(basePath) {
94
94
  simulationSummary: import_path.default.join(basePath, "simulation_summary.json"),
95
95
  statsPayouts: import_path.default.join(basePath, "stats_payouts.json"),
96
96
  statsSummary: import_path.default.join(basePath, "stats_summary.json"),
97
- statsRecords: import_path.default.join(basePath, "stats_records.json")
97
+ statsRecords: import_path.default.join(basePath, "stats_records.json"),
98
+ frontendConfig: import_path.default.join(basePath, "frontend_config.json")
98
99
  };
99
100
  }
100
101
  function createTemporaryFilePaths(basePath, tempFolder) {
@@ -1468,19 +1469,6 @@ var Book = class {
1468
1469
  data: copy(event.data)
1469
1470
  });
1470
1471
  }
1471
- /**
1472
- * Intended for internal use only.
1473
- */
1474
- _serialize() {
1475
- return {
1476
- id: this.id,
1477
- criteria: this.criteria,
1478
- events: this.events,
1479
- payout: this.payout,
1480
- basegameWins: this.basegameWins,
1481
- freespinsWins: this.freespinsWins
1482
- };
1483
- }
1484
1472
  };
1485
1473
 
1486
1474
  // src/wallet/index.ts
@@ -1649,7 +1637,7 @@ var Wallet = class {
1649
1637
  this.currentWin = process2(this.currentWin);
1650
1638
  this.cumulativeWins += this.currentWin;
1651
1639
  let spinTypeWins = 0;
1652
- for (const spinType of Object.keys(this.currentWinPerSpinType)) {
1640
+ for (const spinType in this.currentWinPerSpinType) {
1653
1641
  const st = spinType;
1654
1642
  const spinTypeWin = process2(this.currentWinPerSpinType[st]);
1655
1643
  this.cumulativeWinsPerSpinType[st] += spinTypeWin;
@@ -2454,9 +2442,9 @@ var Simulation = class {
2454
2442
  }
2455
2443
  const chunkIndex = this.bookChunkIndexes.get(index);
2456
2444
  const bookChunkPath = this.PATHS.booksChunk(mode, index, chunkIndex);
2457
- const data = this.bookBuffers.get(index).join("\n") + "\n";
2445
+ const bookLines = this.bookBuffers.get(index);
2458
2446
  await (0, import_promises.pipeline)(
2459
- import_stream.Readable.from([Buffer.from(data, "utf8")]),
2447
+ import_stream.Readable.from(bookLines),
2460
2448
  import_zlib.default.createZstdCompress(),
2461
2449
  import_fs3.default.createWriteStream(bookChunkPath)
2462
2450
  );
@@ -2537,50 +2525,51 @@ var Simulation = class {
2537
2525
  }
2538
2526
  }
2539
2527
  writeChain = writeChain.then(async () => {
2540
- const book = msg.book;
2541
- const bookData = {
2542
- id: book.id,
2543
- payoutMultiplier: book.payout,
2544
- events: book.events
2545
- };
2546
- if (!this.summary[mode]?.criteria[book.criteria]) {
2547
- this.summary[mode].criteria[book.criteria] = {
2528
+ const bookId = msg.bookId;
2529
+ const bookCriteria = msg.bookCriteria;
2530
+ const bookPayout = msg.bookPayout;
2531
+ const bookBasegameWins = msg.bookBasegameWins;
2532
+ const bookFreespinsWins = msg.bookFreespinsWins;
2533
+ const bookLine = msg.bookLine;
2534
+ const bookLineWithNewline = bookLine + "\n";
2535
+ if (!this.summary[mode]?.criteria[bookCriteria]) {
2536
+ this.summary[mode].criteria[bookCriteria] = {
2548
2537
  numSims: 0,
2549
2538
  bsWins: 0,
2550
2539
  fsWins: 0,
2551
2540
  rtp: 0
2552
2541
  };
2553
2542
  }
2554
- const bsWins = round(book.basegameWins, 4);
2555
- const fsWins = round(book.freespinsWins, 4);
2556
- this.summary[mode].criteria[book.criteria].numSims += 1;
2543
+ const bsWins = round(bookBasegameWins, 4);
2544
+ const fsWins = round(bookFreespinsWins, 4);
2545
+ const criteria = this.summary[mode].criteria[bookCriteria];
2546
+ criteria.numSims += 1;
2557
2547
  this.summary[mode].total.bsWins += bsWins;
2558
2548
  this.summary[mode].total.fsWins += fsWins;
2559
- this.summary[mode].criteria[book.criteria].bsWins += bsWins;
2560
- this.summary[mode].criteria[book.criteria].fsWins += fsWins;
2561
- const bookLine = JSON.stringify(bookData);
2562
- const lineSize = Buffer.byteLength(bookLine + "\n", "utf8");
2549
+ criteria.bsWins += bsWins;
2550
+ criteria.fsWins += fsWins;
2551
+ const lineSize = Buffer.byteLength(bookLineWithNewline, "utf8");
2563
2552
  if (this.bookBuffers.has(index)) {
2564
- this.bookBuffers.get(index).push(bookLine);
2553
+ this.bookBuffers.get(index).push(bookLineWithNewline);
2565
2554
  this.bookBufferSizes.set(
2566
2555
  index,
2567
2556
  this.bookBufferSizes.get(index) + lineSize
2568
2557
  );
2569
2558
  } else {
2570
- this.bookBuffers.set(index, [bookLine]);
2559
+ this.bookBuffers.set(index, [bookLineWithNewline]);
2571
2560
  this.bookBufferSizes.set(index, lineSize);
2572
2561
  }
2573
2562
  if (!this.tempBookIndexPaths.includes(booksIndexPath)) {
2574
2563
  this.tempBookIndexPaths.push(booksIndexPath);
2575
2564
  }
2576
2565
  booksIndexBatch.push(
2577
- `${book.id},${index},${this.bookChunkIndexes.get(index) || 0}
2566
+ `${bookId},${index},${this.bookChunkIndexes.get(index) || 0}
2578
2567
  `
2579
2568
  );
2580
- lookupBatch.push(`${book.id},1,${Math.round(book.payout)}
2569
+ lookupBatch.push(`${bookId},1,${Math.round(bookPayout)}
2581
2570
  `);
2582
2571
  lookupSegBatch.push(
2583
- `${book.id},${book.criteria},${book.basegameWins},${book.freespinsWins}
2572
+ `${bookId},${bookCriteria},${bookBasegameWins},${bookFreespinsWins}
2584
2573
  `
2585
2574
  );
2586
2575
  if (booksIndexBatch.length >= WRITE_BATCH_SIZE) {
@@ -2589,15 +2578,10 @@ var Simulation = class {
2589
2578
  if (this.bookBufferSizes.get(index) >= 10 * 1024 * 1024) {
2590
2579
  await flushBookChunk();
2591
2580
  }
2592
- if (this.recordsWriteStream) {
2593
- for (const record of msg.records) {
2594
- const recordPrefix = this.hasWrittenRecord ? "\n" : "";
2595
- await write(
2596
- this.recordsWriteStream,
2597
- recordPrefix + JSON.stringify(record)
2598
- );
2599
- this.hasWrittenRecord = true;
2600
- }
2581
+ if (this.recordsWriteStream && typeof msg.recordsLines === "string" && msg.recordsLines.length) {
2582
+ const recordPrefix = this.hasWrittenRecord ? "\n" : "";
2583
+ await write(this.recordsWriteStream, recordPrefix + msg.recordsLines);
2584
+ this.hasWrittenRecord = true;
2601
2585
  }
2602
2586
  this.wallet.mergeSerialized(msg.wallet);
2603
2587
  worker.postMessage({ type: "credit", amount: 1 });
@@ -2688,9 +2672,11 @@ var Simulation = class {
2688
2672
  });
2689
2673
  }
2690
2674
  }
2691
- ctx.services.wallet._getWallet().writePayoutToBook(ctx);
2692
- ctx.services.wallet._getWallet().confirmWins(ctx);
2693
- if (ctx.services.data._getBook().payout >= ctx.config.maxWinX) {
2675
+ const wallet = ctx.services.wallet._getWallet();
2676
+ wallet.writePayoutToBook(ctx);
2677
+ wallet.confirmWins(ctx);
2678
+ const book = ctx.services.data._getBook();
2679
+ if (book.payout >= ctx.config.maxWinX) {
2694
2680
  ctx.state.triggeredMaxWin = true;
2695
2681
  }
2696
2682
  ctx.services.data.record({
@@ -2698,12 +2684,24 @@ var Simulation = class {
2698
2684
  });
2699
2685
  ctx.config.hooks.onSimulationAccepted?.(ctx);
2700
2686
  this.confirmRecords(ctx);
2687
+ const bookLine = JSON.stringify({
2688
+ id: book.id,
2689
+ payoutMultiplier: book.payout,
2690
+ events: book.events
2691
+ });
2692
+ const records = ctx.services.data._getRecords();
2693
+ const recordsLines = records.length > 0 ? records.map((r) => JSON.stringify(r)).join("\n") : "";
2701
2694
  import_worker_threads2.parentPort?.postMessage({
2702
2695
  type: "complete",
2703
2696
  simId,
2704
- book: ctx.services.data._getBook()._serialize(),
2705
- wallet: ctx.services.wallet._getWallet().serialize(),
2706
- records: ctx.services.data._getRecords()
2697
+ bookLine,
2698
+ bookId: book.id,
2699
+ bookCriteria: book.criteria,
2700
+ bookPayout: book.payout,
2701
+ bookBasegameWins: book.basegameWins,
2702
+ bookFreespinsWins: book.freespinsWins,
2703
+ wallet: wallet.serialize(),
2704
+ recordsLines
2707
2705
  });
2708
2706
  }
2709
2707
  initCreditListener() {
@@ -3749,6 +3747,43 @@ async function rustProgram(...args) {
3749
3747
 
3750
3748
  // src/slot-game/index.ts
3751
3749
  var import_worker_threads5 = require("worker_threads");
3750
+
3751
+ // src/utils/frontend-config.ts
3752
+ function createFrontendConfig(config, meta) {
3753
+ const path9 = meta.paths.frontendConfig;
3754
+ const gameModes = Object.values(config.gameModes).map((gm) => ({
3755
+ name: gm.name,
3756
+ cost: gm.cost,
3757
+ rtp: gm.rtp
3758
+ }));
3759
+ const reelSets = /* @__PURE__ */ new Map();
3760
+ Object.values(config.gameModes).forEach((gm) => {
3761
+ gm.reelSets.forEach((reelSet) => {
3762
+ reelSet.associatedGameModeName = gm.name;
3763
+ reelSet.generateReels(config);
3764
+ if (!reelSets.has(reelSet.id)) {
3765
+ reelSets.set(
3766
+ reelSet.id,
3767
+ reelSet.reels.map((reel) => reel.map((s) => s.id))
3768
+ );
3769
+ }
3770
+ });
3771
+ });
3772
+ const frontendConfig = {
3773
+ name: config.name,
3774
+ maxWin: config.maxWinX,
3775
+ padSymbols: config.padSymbols,
3776
+ symbols: Array.from(config.symbols.values()).map((s) => ({
3777
+ id: s.id,
3778
+ pays: s.pays
3779
+ })),
3780
+ gameModes,
3781
+ reelSets: Object.fromEntries(reelSets)
3782
+ };
3783
+ writeJsonFile(path9, frontendConfig);
3784
+ }
3785
+
3786
+ // src/slot-game/index.ts
3752
3787
  var SlotGame = class _SlotGame {
3753
3788
  configOpts;
3754
3789
  simulation;
@@ -3836,7 +3871,10 @@ var SlotGame = class _SlotGame {
3836
3871
  this.runAnalysis(opts.analysisOpts || { gameModes: [] });
3837
3872
  }
3838
3873
  }
3839
- if (import_worker_threads5.isMainThread) console.log("Done!");
3874
+ if (import_worker_threads5.isMainThread) {
3875
+ createFrontendConfig(this.getConfig(), this.getMetadata());
3876
+ console.log("Done!");
3877
+ }
3840
3878
  }
3841
3879
  /**
3842
3880
  * Gets the game configuration.