@slot-engine/core 0.2.0 → 0.2.1

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
@@ -50,6 +50,7 @@ type PermanentFilePaths = {
50
50
  booksIndexMeta: (mode: string) => string;
51
51
  booksChunk: (mode: string, worker: number, chunk: number) => string;
52
52
  booksCompressed: (mode: string) => string;
53
+ booksUncompressed: (mode: string) => string;
53
54
  lookupTable: (mode: string) => string;
54
55
  lookupTableIndex: (mode: string) => string;
55
56
  lookupTableSegmented: (mode: string) => string;
@@ -175,6 +176,7 @@ declare class Simulation {
175
176
  readonly gameConfig: GameConfig & GameMetadata;
176
177
  readonly simRunsAmount: Partial<Record<string, number>>;
177
178
  readonly concurrency: number;
179
+ readonly makeUncompressedBooks: boolean;
178
180
  private debug;
179
181
  private actualSims;
180
182
  private wallet;
@@ -265,6 +267,7 @@ declare class Simulation {
265
267
  */
266
268
  confirmRecords(ctx: GameContext): void;
267
269
  printSimulationSummary(): Promise<void>;
270
+ private sendSimulationStatus;
268
271
  }
269
272
  type SimulationOptions = {
270
273
  /**
@@ -293,6 +296,10 @@ type SimulationOptions = {
293
296
  * Default: 50
294
297
  */
295
298
  maxDiskBuffer?: number;
299
+ /**
300
+ * Whether to generate uncompressed book files alongside compressed ones.
301
+ */
302
+ makeUncompressedBooks?: boolean;
296
303
  };
297
304
  type SimulationConfigOptions = {
298
305
  debug?: boolean;
package/dist/index.d.ts CHANGED
@@ -50,6 +50,7 @@ type PermanentFilePaths = {
50
50
  booksIndexMeta: (mode: string) => string;
51
51
  booksChunk: (mode: string, worker: number, chunk: number) => string;
52
52
  booksCompressed: (mode: string) => string;
53
+ booksUncompressed: (mode: string) => string;
53
54
  lookupTable: (mode: string) => string;
54
55
  lookupTableIndex: (mode: string) => string;
55
56
  lookupTableSegmented: (mode: string) => string;
@@ -175,6 +176,7 @@ declare class Simulation {
175
176
  readonly gameConfig: GameConfig & GameMetadata;
176
177
  readonly simRunsAmount: Partial<Record<string, number>>;
177
178
  readonly concurrency: number;
179
+ readonly makeUncompressedBooks: boolean;
178
180
  private debug;
179
181
  private actualSims;
180
182
  private wallet;
@@ -265,6 +267,7 @@ declare class Simulation {
265
267
  */
266
268
  confirmRecords(ctx: GameContext): void;
267
269
  printSimulationSummary(): Promise<void>;
270
+ private sendSimulationStatus;
268
271
  }
269
272
  type SimulationOptions = {
270
273
  /**
@@ -293,6 +296,10 @@ type SimulationOptions = {
293
296
  * Default: 50
294
297
  */
295
298
  maxDiskBuffer?: number;
299
+ /**
300
+ * Whether to generate uncompressed book files alongside compressed ones.
301
+ */
302
+ makeUncompressedBooks?: boolean;
296
303
  };
297
304
  type SimulationConfigOptions = {
298
305
  debug?: boolean;
package/dist/index.js CHANGED
@@ -79,6 +79,7 @@ function createPermanentFilePaths(basePath) {
79
79
  `books_${mode}_chunk_${worker}-${chunk}.jsonl.zst`
80
80
  ),
81
81
  booksCompressed: (mode) => import_path.default.join(basePath, "publish_files", `books_${mode}.jsonl.zst`),
82
+ booksUncompressed: (mode) => import_path.default.join(basePath, `books_${mode}.jsonl`),
82
83
  lookupTable: (mode) => import_path.default.join(basePath, `lookUpTable_${mode}.csv`),
83
84
  lookupTableIndex: (mode) => import_path.default.join(basePath, `lookUpTable_${mode}.index`),
84
85
  lookupTableSegmented: (mode) => import_path.default.join(basePath, `lookUpTableSegmented_${mode}.csv`),
@@ -1799,6 +1800,8 @@ var TerminalUi = class {
1799
1800
  logs = [];
1800
1801
  logScrollOffset = 0;
1801
1802
  isScrolled = false;
1803
+ maxLogs = 500;
1804
+ totalLogs = 0;
1802
1805
  minWidth = 50;
1803
1806
  minHeight = 12;
1804
1807
  isRendering = false;
@@ -1824,12 +1827,13 @@ var TerminalUi = class {
1824
1827
  this.scrollDown();
1825
1828
  } else if (key === "l") {
1826
1829
  this.scrollToBottom();
1827
- } else if (key === "") {
1830
+ } else if (key === "q" || key === "") {
1828
1831
  this.stop();
1829
1832
  process.exit(0);
1830
1833
  }
1831
1834
  };
1832
1835
  process.stdout.on("resize", this.resizeHandler);
1836
+ process.on("SIGINT", this.sigintHandler);
1833
1837
  }
1834
1838
  get terminalWidth() {
1835
1839
  return process.stdout.columns || 80;
@@ -1851,7 +1855,6 @@ var TerminalUi = class {
1851
1855
  }
1852
1856
  this.render();
1853
1857
  this.renderInterval = setInterval(() => this.render(), 100);
1854
- process.on("SIGINT", this.sigintHandler);
1855
1858
  }
1856
1859
  stop() {
1857
1860
  if (this.renderInterval) {
@@ -1879,7 +1882,16 @@ var TerminalUi = class {
1879
1882
  this.totalSims = opts.totalSims;
1880
1883
  }
1881
1884
  log(message) {
1882
- this.logs.push({ i: this.logs.length, m: message });
1885
+ this.logs.push({ i: this.totalLogs, m: message });
1886
+ this.totalLogs++;
1887
+ if (this.logs.length > this.maxLogs) {
1888
+ const excess = this.logs.length - this.maxLogs;
1889
+ this.logs.splice(0, excess);
1890
+ this.logScrollOffset = Math.min(
1891
+ this.logScrollOffset,
1892
+ Math.max(0, this.logs.length - this.getLogAreaHeight())
1893
+ );
1894
+ }
1883
1895
  if (!this.isScrolled) this.scrollToBottom();
1884
1896
  }
1885
1897
  scrollUp(lines = 1) {
@@ -2044,6 +2056,7 @@ var Simulation = class {
2044
2056
  gameConfig;
2045
2057
  simRunsAmount;
2046
2058
  concurrency;
2059
+ makeUncompressedBooks;
2047
2060
  debug = false;
2048
2061
  actualSims = 0;
2049
2062
  wallet = new Wallet();
@@ -2072,6 +2085,7 @@ var Simulation = class {
2072
2085
  const { config, metadata } = createGameConfig(gameConfigOpts);
2073
2086
  this.gameConfig = { ...config, ...metadata };
2074
2087
  this.gameConfigOpts = gameConfigOpts;
2088
+ this.makeUncompressedBooks = opts.makeUncompressedBooks || false;
2075
2089
  this.simRunsAmount = opts.simRunsAmount || {};
2076
2090
  this.concurrency = (opts.concurrency || 6) >= 2 ? opts.concurrency || 6 : 2;
2077
2091
  this.maxPendingSims = opts.maxPendingSims ?? 25;
@@ -2149,9 +2163,7 @@ var Simulation = class {
2149
2163
  const startTime = Date.now();
2150
2164
  statusMessage = `Simulating mode "${mode}" with ${this.simRunsAmount[mode]} runs.`;
2151
2165
  this.tui?.log(statusMessage);
2152
- if (this.socket && this.panelActive) {
2153
- this.socket.emit("simulationStatus", statusMessage);
2154
- }
2166
+ this.sendSimulationStatus(statusMessage);
2155
2167
  const runs = this.simRunsAmount[mode] || 0;
2156
2168
  if (runs <= 0) continue;
2157
2169
  if (!configuredGameModes.includes(mode)) {
@@ -2188,9 +2200,7 @@ var Simulation = class {
2188
2200
  createDirIfNotExists(this.PATHS.publishFiles);
2189
2201
  statusMessage = `Writing final files for game mode "${mode}". This may take a while...`;
2190
2202
  this.tui?.log(statusMessage);
2191
- if (this.socket && this.panelActive) {
2192
- this.socket.emit("simulationStatus", statusMessage);
2193
- }
2203
+ this.sendSimulationStatus(statusMessage);
2194
2204
  writeFile(
2195
2205
  this.PATHS.booksIndexMeta(mode),
2196
2206
  JSON.stringify(
@@ -2245,13 +2255,43 @@ var Simulation = class {
2245
2255
  }
2246
2256
  await this.writeRecords(mode);
2247
2257
  this.writeIndexJson();
2258
+ if (this.makeUncompressedBooks) {
2259
+ statusMessage = `Creating decompressed book file for mode "${mode}". This may take a while...`;
2260
+ this.tui?.log(statusMessage);
2261
+ this.sendSimulationStatus(statusMessage);
2262
+ const uncompressedBooksPath = this.PATHS.booksUncompressed(mode);
2263
+ const outputStream = import_fs3.default.createWriteStream(uncompressedBooksPath, {
2264
+ highWaterMark: this.streamHighWaterMark
2265
+ });
2266
+ try {
2267
+ for (const { worker, chunks: chunks2 } of this.bookIndexMetas) {
2268
+ for (let chunk = 0; chunk < chunks2; chunk++) {
2269
+ const bookChunkPath = this.PATHS.booksChunk(mode, worker, chunk);
2270
+ if (!import_fs3.default.existsSync(bookChunkPath)) continue;
2271
+ const inputStream = import_fs3.default.createReadStream(bookChunkPath);
2272
+ const compress = import_zlib.default.createZstdDecompress();
2273
+ for await (const decompChunk of inputStream.pipe(compress)) {
2274
+ if (!outputStream.write(decompChunk)) {
2275
+ await new Promise((r) => outputStream.once("drain", () => r()));
2276
+ }
2277
+ }
2278
+ }
2279
+ }
2280
+ outputStream.end();
2281
+ await new Promise((r) => outputStream.on("finish", () => r()));
2282
+ } catch (error) {
2283
+ statusMessage = import_chalk2.default.yellow(
2284
+ `Error creating uncompressed book file: ${error.message}`
2285
+ );
2286
+ this.tui?.log(statusMessage);
2287
+ this.sendSimulationStatus(statusMessage);
2288
+ }
2289
+ }
2248
2290
  const endTime = Date.now();
2249
2291
  const prettyTime = new Date(endTime - startTime).toISOString().slice(11, -1);
2250
2292
  statusMessage = `Mode ${mode} done! Time taken: ${prettyTime}`;
2251
2293
  this.tui?.log(statusMessage);
2252
- if (this.socket && this.panelActive) {
2253
- this.socket.emit("simulationStatus", statusMessage);
2254
- }
2294
+ this.sendSimulationStatus(statusMessage);
2255
2295
  }
2256
2296
  this.tui?.stop();
2257
2297
  await this.printSimulationSummary();
@@ -2453,7 +2493,7 @@ var Simulation = class {
2453
2493
  `
2454
2494
  )
2455
2495
  ]);
2456
- if (this.bookBufferSizes.get(index) >= 12 * 1024 * 1024) {
2496
+ if (this.bookBufferSizes.get(index) >= 10 * 1024 * 1024) {
2457
2497
  await flushBookChunk();
2458
2498
  }
2459
2499
  if (this.recordsWriteStream) {
@@ -2899,6 +2939,11 @@ var Simulation = class {
2899
2939
  });
2900
2940
  }
2901
2941
  }
2942
+ sendSimulationStatus(message) {
2943
+ if (this.socket && this.panelActive) {
2944
+ this.socket.emit("simulationStatus", message);
2945
+ }
2946
+ }
2902
2947
  };
2903
2948
 
2904
2949
  // src/analysis/index.ts