silphscope 1.4.12 → 1.4.14

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
@@ -55,7 +55,7 @@ const rom = fs.readFileSync("pokefirered.gba"); // replace with path to your own
55
55
  await renderAllGraphics(rom, {
56
56
  concurrency: 4, // handles how many concurrent promises are run. Set to 1 to run sequentially and conversly increase to run more promises at once (don't set too high though if your CPU / I/O can't handle it then it might actually be slower...)
57
57
  pngFilterType: 0, // view the explanation for this above
58
- pngCompression: 4, // same thing :p explanation above
58
+ pngCompressionLevel: 4, // same thing :p explanation above
59
59
  outputMonDir: "./Assets/monImages", // must I explain?
60
60
  outputIconDir: "./Assets/Icons", // same thing here :p
61
61
  outputTrainerDir: "./Assets/Trainers", // ...
@@ -78,7 +78,7 @@ const rom = fs.readFileSync("pokefirered.gba")// once again replace with the pat
78
78
  await renderAllMons(rom, {
79
79
  concurrency: 4, // handles how many concurrent promises are run. Set to 1 to run sequentially and conversly increase to run more promises at once (don't set too high though if your CPU / I/O can't handle it then it might actually be slower...)
80
80
  pngFilterType: 0, // explanation above
81
- pngCompression: 4, // explanation above
81
+ pngCompressionLevel: 4, // explanation above
82
82
  outputDir: "./Assets/monImages", // do I actually have to explain?
83
83
  icon: true, // set to false if you don't want icons I guess...
84
84
  footprint: true, // same as the above...
@@ -94,7 +94,7 @@ const rom = fs.readFileSync("pokefirered.gba")// find your own rom and so on :l
94
94
  await renderAllIcons(rom, {
95
95
  concurrency: 4, // handles how many concurrent promises are run. Set to 1 to run sequentially and conversly increase to run more promises at once (don't set too high though if your CPU / I/O can't handle it then it might actually be slower...)
96
96
  pngFilterType: 0, // explanation above
97
- pngCompression: 4, // explanation above
97
+ pngCompressionLevel: 4, // explanation above
98
98
  outputDir: "./Assets/Icons" // no comment (wait... that was a comment :p)
99
99
  });
100
100
  ```
@@ -108,7 +108,7 @@ const rom = fs.readFileSync("pokefirered.gba") // stuff stuff stuff
108
108
  await renderAllTrainers(rom, {
109
109
  concurrency: 4, // handles how many concurrent promises are run. Set to 1 to run sequentially and conversly increase to run more promises at once (don't set too high though if your CPU / I/O can't handle it then it might actually be slower...)
110
110
  pngFilterType: 0, // explanation above
111
- pngCompression: 4, // explanation above
111
+ pngCompressionLevel: 4, // explanation above
112
112
  outputDir: "./Assets/trainers", // more stuff
113
113
  trainerBackPics: true, // renders the like 8 trainer back pics
114
114
  })
@@ -123,7 +123,7 @@ const rom = fs.readFileSync("pokefirered.gba") // stuff stuff stuff (more stuff!
123
123
  await renderAllMoves(rom, {
124
124
  concurrency: 4, // handles how many concurrent promises are run. Set to 1 to run sequentially and conversly increase to run more promises at once (don't set too high though if your CPU / I/O can't handle it then it might actually be slower...)
125
125
  pngFilterType: 0, // explanation above
126
- pngCompression: 4, // explanation above
126
+ pngCompressionLevel: 4, // explanation above
127
127
  outputDir: "./Assets/trainers", // (incredibly) more stuff
128
128
  renderMasterImage: true, // kinda forgot about this... basically it renders a uncut image of the move anim if you like
129
129
  sortUnused: true, // sorts unused moves into a sub-directory
@@ -139,7 +139,7 @@ const rom = fs.readFileSync("./path/to/your/rom.gba") // the file path explains
139
139
  await renderAllBalls(rom, {
140
140
  concurrency: 4, // handles how many concurrent promises are run. Set to 1 to run sequentially and conversly increase to run more promises at once (don't set too high though if your CPU / I/O can't handle it then it might actually be slower...)
141
141
  pngFilterType: 0, // explanation above
142
- pngCompression: 4, // explanation above
142
+ pngCompressionLevel: 4, // explanation above
143
143
  outputDir: "./Assets/Balls",
144
144
  ballParticles: true, // set to false if you don't want the ball particles :p
145
145
  renderMasterBallImage: true, // set to false if you don't want the uncut image
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "silphscope",
3
- "version": "1.4.12",
3
+ "version": "1.4.14",
4
4
  "description": "A firered/leafgreen ROM asset extractor for use in web applications",
5
5
  "main": "main.js",
6
6
  "exports": {
@@ -41,6 +41,7 @@ function isValidFilterType(filterTypeValue) {
41
41
  }
42
42
 
43
43
  export async function renderAllMons(rom, options = {}) {
44
+ const start = performance.now();
44
45
  if (!rom || !(rom instanceof Uint8Array || Buffer.isBuffer(rom))) {
45
46
  throw new TypeError("renderAllMons(rom, options) requires rom Buffer/Uint8Array as first argument");
46
47
  }
@@ -51,6 +52,9 @@ export async function renderAllMons(rom, options = {}) {
51
52
  concurrency = 4,
52
53
  pngFilterType = 0,
53
54
  pngCompressionLevel = 4,
55
+ verboseLogs = true,
56
+ showSummary = true,
57
+ returnFileBuffer = false,
54
58
  icon = true,
55
59
  footprint = true,
56
60
  } = options;
@@ -69,34 +73,65 @@ export async function renderAllMons(rom, options = {}) {
69
73
 
70
74
  const config = getRomConfig(rom);
71
75
  const reader = new RomReader(rom, config);
76
+ let totalFileCount = 0;
77
+ const finalResults = returnFileBuffer? [] : null;
72
78
 
73
79
  if (concurrency > 1) {
74
80
  await mapLimit(Object.keys(providedMons), concurrency, async (monName) => { // so in theory we should be running the function 4 times concurrently now...
75
- await renderMon(monName, providedMons, reader, rom, {
81
+ const renderMonData = await renderMon(monName, providedMons, reader, rom, {
76
82
  side: ["front", "back"],
77
83
  variant: ["normal", "shiny"],
78
84
  icon,
79
85
  footprint,
80
86
  pngFilterType,
81
87
  pngCompressionLevel,
88
+ returnFileBuffer,
82
89
  outputDir,
83
90
  });
84
- console.log(`Done: ${monName}`);
91
+ if (verboseLogs) {
92
+ console.log(`Done: ${monName}`);
93
+ }
94
+ totalFileCount += renderMonData.fullFileCount;
95
+ if (returnFileBuffer) {
96
+ finalResults.push(...renderMonData.results);
97
+ }
85
98
  });
86
99
  } else {
87
100
  for (const monName of Object.keys(providedMons)) {
88
- await renderMon(monName, providedMons, reader, rom, {
101
+ const renderMonData = await renderMon(monName, providedMons, reader, rom, {
89
102
  side: ["front", "back"],
90
103
  variant: ["normal", "shiny"],
91
104
  icon,
92
105
  footprint,
93
106
  pngFilterType,
94
107
  pngCompressionLevel,
108
+ returnFileBuffer,
95
109
  outputDir,
96
110
  });
97
- console.log(`Done: ${monName}`);
111
+ if (verboseLogs) {
112
+ console.log(`Done: ${monName}`);
113
+ }
114
+ totalFileCount += renderMonData.fullFileCount;
115
+ if (returnFileBuffer) {
116
+ finalResults.push(...renderMonData.results);
117
+ }
98
118
  }
99
119
  }
120
+
121
+ const elapsed = ((performance.now() - start) / 1000).toFixed(2);
122
+
123
+ if (showSummary) {
124
+ console.log(`
125
+ renderAllMons() Output Summary:
126
+ Rendered ${Object.keys(providedMons).length} Mons amounting to:
127
+ ${totalFileCount} Files written
128
+ Done in ${elapsed}s with SilphScope`);
129
+ }
130
+
131
+ return {
132
+ totalFileCount,
133
+ ...(returnFileBuffer && { finalResults }),
134
+ };
100
135
  }
101
136
 
102
137
  export async function renderAllIcons(rom, options = {}) {
@@ -109,6 +144,7 @@ export async function renderAllIcons(rom, options = {}) {
109
144
  concurrency = 4,
110
145
  pngFilterType = 0,
111
146
  pngCompressionLevel = 4,
147
+ verboseLogs = true,
112
148
  outputDir = "./out",
113
149
  } = options;
114
150
 
@@ -134,7 +170,9 @@ export async function renderAllIcons(rom, options = {}) {
134
170
  pngCompressionLevel,
135
171
  outputDir,
136
172
  });
137
- console.log(`Done: ${itemName}`);
173
+ if (verboseLogs) {
174
+ console.log(`Done: ${itemName}`);
175
+ }
138
176
  });
139
177
  } else {
140
178
  for (const itemName of Object.keys(providedIcons)) {
@@ -143,7 +181,9 @@ export async function renderAllIcons(rom, options = {}) {
143
181
  pngCompressionLevel,
144
182
  outputDir,
145
183
  });
146
- console.log(`Done: ${itemName}`);
184
+ if (verboseLogs) {
185
+ console.log(`Done: ${itemName}`);
186
+ }
147
187
  }
148
188
  }
149
189
  }
@@ -160,6 +200,7 @@ export async function renderAllTrainers(rom, options = {}) {
160
200
  concurrency = 4,
161
201
  pngFilterType = 0,
162
202
  pngCompressionLevel = 4,
203
+ verboseLogs = true,
163
204
  outputDir = "./out",
164
205
  } = options;
165
206
 
@@ -186,7 +227,9 @@ export async function renderAllTrainers(rom, options = {}) {
186
227
  pngCompressionLevel,
187
228
  outputDir
188
229
  });
189
- console.log(`Done: ${trainerName}`);
230
+ if (verboseLogs) {
231
+ console.log(`Done: ${trainerName}`);
232
+ }
190
233
  });
191
234
  } else {
192
235
  for (const trainerName of Object.keys(providedTrainers)) {
@@ -196,7 +239,9 @@ export async function renderAllTrainers(rom, options = {}) {
196
239
  pngCompressionLevel,
197
240
  outputDir
198
241
  });
199
- console.log(`Done: ${trainerName}`);
242
+ if (verboseLogs) {
243
+ console.log(`Done: ${trainerName}`);
244
+ }
200
245
  }
201
246
  }
202
247
  }
@@ -211,6 +256,7 @@ export async function renderAllMoves(rom, options = {}) {
211
256
  concurrency = 4,
212
257
  pngFilterType = 0,
213
258
  pngCompressionLevel = 4,
259
+ verboseLogs = true,
214
260
  outputDir = "./out",
215
261
  renderMasterImage = true,
216
262
  sortUnused = true,
@@ -240,7 +286,9 @@ export async function renderAllMoves(rom, options = {}) {
240
286
  renderMasterImage,
241
287
  sortUnused,
242
288
  });
243
- console.log(`Done: ${moveName}`);
289
+ if (verboseLogs) {
290
+ console.log(`Done: ${moveName}`);
291
+ }
244
292
  });
245
293
  } else {
246
294
  for (const moveName of Object.keys(providedMoves)) {
@@ -251,7 +299,9 @@ export async function renderAllMoves(rom, options = {}) {
251
299
  renderMasterImage,
252
300
  sortUnused,
253
301
  });
254
- console.log(`Done: ${moveName}`);
302
+ if (verboseLogs) {
303
+ console.log(`Done: ${moveName}`);
304
+ }
255
305
  }
256
306
  }
257
307
  }
@@ -266,6 +316,7 @@ export async function renderAllBalls(rom, options = {}) {
266
316
  concurrency = 4,
267
317
  pngFilterType = 0,
268
318
  pngCompressionLevel = 4,
319
+ verboseLogs = true,
269
320
  outputDir = "./out",
270
321
  ballParticles = true,
271
322
  renderMasterBallImage = true,
@@ -297,7 +348,9 @@ export async function renderAllBalls(rom, options = {}) {
297
348
  renderMasterBallImage,
298
349
  renderMasterBallParticleImage,
299
350
  });
300
- console.log(`Done: ${ballName}`);
351
+ if (verboseLogs) {
352
+ console.log(`Done: ${ballName}`);
353
+ }
301
354
  })
302
355
  } else {
303
356
  for (const ballName of Object.keys(providedBalls)) {
@@ -309,7 +362,9 @@ export async function renderAllBalls(rom, options = {}) {
309
362
  renderMasterBallImage,
310
363
  renderMasterBallParticleImage,
311
364
  });
312
- console.log(`Done: ${ballName}`);
365
+ if (verboseLogs) {
366
+ console.log(`Done: ${ballName}`);
367
+ }
313
368
  }
314
369
  }
315
370
  }
@@ -323,6 +378,7 @@ export async function renderAllGraphics(rom, options = {}) { // eventually I wil
323
378
  concurrency = 4,
324
379
  pngFilterType = 0,
325
380
  pngCompressionLevel = 4,
381
+ verboseLogs = true,
326
382
  outputMonDir = "./out/mons",
327
383
  outputIconDir = "./out/icons",
328
384
  outputTrainerDir = "./out/trainers",
@@ -345,6 +401,7 @@ export async function renderAllGraphics(rom, options = {}) { // eventually I wil
345
401
  concurrency,
346
402
  pngFilterType,
347
403
  pngCompressionLevel,
404
+ verboseLogs,
348
405
  outputDir: outputMonDir,
349
406
  icon: true,
350
407
  footprint: true,
@@ -354,6 +411,7 @@ export async function renderAllGraphics(rom, options = {}) { // eventually I wil
354
411
  concurrency,
355
412
  pngFilterType,
356
413
  pngCompressionLevel,
414
+ verboseLogs,
357
415
  outputDir: outputIconDir,
358
416
  });
359
417
 
@@ -361,6 +419,7 @@ export async function renderAllGraphics(rom, options = {}) { // eventually I wil
361
419
  concurrency,
362
420
  pngFilterType,
363
421
  pngCompressionLevel,
422
+ verboseLogs,
364
423
  outputDir: outputTrainerDir,
365
424
  trainerBackPics: true,
366
425
  });
@@ -369,6 +428,7 @@ export async function renderAllGraphics(rom, options = {}) { // eventually I wil
369
428
  concurrency,
370
429
  pngFilterType,
371
430
  pngCompressionLevel,
431
+ verboseLogs,
372
432
  outputDir: outputMoveDir,
373
433
  renderMasterImage: true,
374
434
  sortUnused: sortUnusedMoves,
@@ -378,6 +438,7 @@ export async function renderAllGraphics(rom, options = {}) { // eventually I wil
378
438
  concurrency,
379
439
  pngFilterType,
380
440
  pngCompressionLevel,
441
+ verboseLogs,
381
442
  outputDir: outputBallDir,
382
443
  ballParticles: true,
383
444
  renderMasterBallImage: true,
@@ -17,7 +17,8 @@ const streamToBuffer = (stream) => new Promise((resolve, reject) => {
17
17
  export async function renderMonFoot(monName, mons, reader, rom, options = {}) {
18
18
  const {
19
19
  pngFilterType = null,
20
- pngCompressionType = null,
20
+ pngCompressionLevel = null,
21
+ returnFileBuffer,
21
22
  outputDir = null,
22
23
  } = options;
23
24
 
@@ -25,12 +26,17 @@ export async function renderMonFoot(monName, mons, reader, rom, options = {}) {
25
26
  throw new TypeError("renderMonFoot(..., rom) requires a ROM Buffer/Uint8Array");
26
27
  }
27
28
 
29
+ let fileCount = 0;
28
30
  const mon = mons[monName];
29
31
  if (!mon) {
30
32
  throw new Error(`Missing mon entry for ${monName}`);
31
33
  }
32
34
 
33
- if (monName.includes("UNOWN")) return;
35
+ if (monName.includes("UNOWN")) {
36
+ return {
37
+ fileCount: 0,
38
+ }
39
+ }
34
40
 
35
41
  const footAsset = resolveMonFootprint(mon, reader, monName); // possibly the easiest change ive had to do if it works first try :o
36
42
  if (!footAsset) {
@@ -76,7 +82,7 @@ export async function renderMonFoot(monName, mons, reader, rom, options = {}) {
76
82
  png.data = image;
77
83
  const pngBuffer = PNG.sync.write(png, {
78
84
  filterType: pngFilterType,
79
- deflateLevel: pngCompressionType,
85
+ deflateLevel: pngCompressionLevel,
80
86
  });
81
87
 
82
88
  if (outputDir) {
@@ -84,7 +90,11 @@ export async function renderMonFoot(monName, mons, reader, rom, options = {}) {
84
90
  await fs.promises.mkdir(dir, { recursive: true });
85
91
  const fileName = `${dir}/footprint.png`;
86
92
  await fs.promises.writeFile(fileName, pngBuffer);
93
+ fileCount += 1;
87
94
  }
88
95
 
89
- return pngBuffer;
96
+ return {
97
+ ...(returnFileBuffer && { pngBuffer }),
98
+ fileCount,
99
+ };
90
100
  }
@@ -16,16 +16,18 @@ const streamToBuffer = (stream) => new Promise((resolve, reject) => {
16
16
  });
17
17
 
18
18
  export async function renderMonIcon(monName, mons, reader, rom, options = {}) {
19
- const {
19
+ const {
20
20
  pngFilterType = null,
21
21
  pngCompressionLevel = null,
22
- outputDir = null
22
+ returnFileBuffer = false,
23
+ outputDir = null
23
24
  } = options;
24
25
 
25
26
  if (!rom || !(rom instanceof Uint8Array || Buffer.isBuffer(rom))) {
26
27
  throw new TypeError("renderMonIcon(..., rom) requires a ROM Buffer/Uint8Array");
27
28
  }
28
29
 
30
+ let fileCount = 0;
29
31
  const mon = mons[monName];
30
32
  if (!mon) {
31
33
  throw new Error(`Missing mon entry for ${monName}`);
@@ -41,10 +43,10 @@ export async function renderMonIcon(monName, mons, reader, rom, options = {}) {
41
43
  const height = 64;
42
44
 
43
45
  const image = render4bppImage({
44
- tileData: iconData.data,
45
- paletteData: rawIconPalData.data,
46
- width,
47
- height,
46
+ tileData: iconData.data,
47
+ paletteData: rawIconPalData.data,
48
+ width,
49
+ height,
48
50
  });
49
51
 
50
52
  const frameHeight = 32;
@@ -55,13 +57,13 @@ export async function renderMonIcon(monName, mons, reader, rom, options = {}) {
55
57
  pngFrame1.data = frame1;
56
58
  const pngFrame2 = new PNG({ width, height: frameHeight });
57
59
  pngFrame2.data = frame2;
58
- const buffer1 = PNG.sync.write(pngFrame1, {
60
+ const buffer1 = PNG.sync.write(pngFrame1, {
59
61
  filterType: pngFilterType,
60
- deflateLevel: pngCompressionLevel,
62
+ deflateLevel: pngCompressionLevel,
61
63
  });
62
- const buffer2 = PNG.sync.write(pngFrame2, {
64
+ const buffer2 = PNG.sync.write(pngFrame2, {
63
65
  filterType: pngFilterType,
64
- deflateLevel: pngCompressionLevel,
66
+ deflateLevel: pngCompressionLevel,
65
67
  });
66
68
 
67
69
  if (outputDir) {
@@ -69,10 +71,12 @@ export async function renderMonIcon(monName, mons, reader, rom, options = {}) {
69
71
  await fs.promises.mkdir(dir, { recursive: true });
70
72
  await fs.promises.writeFile(`${dir}/icon_frame1.png`, buffer1);
71
73
  await fs.promises.writeFile(`${dir}/icon_frame2.png`, buffer2);
74
+ fileCount += 2;
72
75
  }
73
76
 
74
77
  return {
75
- frame1: buffer1,
76
- frame2: buffer2,
78
+ ...(returnFileBuffer && { frame1: buffer1 }),
79
+ ...(returnFileBuffer && { frame2: buffer2 }),
80
+ fileCount,
77
81
  };
78
82
  }
@@ -25,6 +25,7 @@ export async function renderMon(monName, mons, reader, rom, options = {}) {
25
25
  footprint = false,
26
26
  pngFilterType = null,
27
27
  pngCompressionLevel = null,
28
+ returnFileBuffer = false,
28
29
  outputDir = null,
29
30
  } = options;
30
31
 
@@ -32,22 +33,35 @@ export async function renderMon(monName, mons, reader, rom, options = {}) {
32
33
  throw new TypeError("renderMon(..., rom) requires a ROM Buffer/Uint8Array");
33
34
  }
34
35
 
36
+ let fullFileCount = 0;
35
37
  const sides = Array.isArray(side) ? side : [side];
36
38
  const variants = Array.isArray(variant) ? variant : [variant];
39
+ const results = returnFileBuffer? [] : null;
37
40
 
38
41
  if (icon === true) {
39
- await renderMonIcon(monName, mons, reader, rom, {
42
+ const monIconData = await renderMonIcon(monName, mons, reader, rom, {
40
43
  pngFilterType,
41
44
  pngCompressionLevel,
45
+ returnFileBuffer,
42
46
  outputDir,
43
47
  });
48
+ fullFileCount += monIconData.fileCount;
49
+ if (returnFileBuffer) {
50
+ results.push(monIconData.frame1);
51
+ results.push(monIconData.frame2);
52
+ }
44
53
  }
45
54
  if (footprint === true) {
46
- await renderMonFoot(monName, mons, reader, rom, {
55
+ const monFootData = await renderMonFoot(monName, mons, reader, rom, {
47
56
  pngFilterType,
48
57
  pngCompressionLevel,
49
- outputDir,
58
+ returnFileBuffer,
59
+ outputDir,
50
60
  });
61
+ fullFileCount += monFootData.fileCount;
62
+ if (returnFileBuffer) {
63
+ results.push(monFootData.pngBuffer);
64
+ }
51
65
  }
52
66
 
53
67
  const mon = mons[monName];
@@ -68,7 +82,6 @@ export async function renderMon(monName, mons, reader, rom, options = {}) {
68
82
  palCache[variant] = extract(monPal, rom).data;
69
83
  }
70
84
 
71
- const results = [];
72
85
  const width = 64;
73
86
  const height = 64;
74
87
  if (outputDir) {
@@ -78,17 +91,17 @@ export async function renderMon(monName, mons, reader, rom, options = {}) {
78
91
  for (const side of sides) {
79
92
  for (const variant of variants) {
80
93
  const image = render4bppImage({
81
- tileData: picCache[side],
82
- paletteData: palCache[variant],
83
- width,
84
- height,
94
+ tileData: picCache[side],
95
+ paletteData: palCache[variant],
96
+ width,
97
+ height,
85
98
  });
86
99
 
87
100
  const png = new PNG({ width, height });
88
101
  png.data = image;
89
- const pngBuffer = PNG.sync.write(png, {
102
+ const pngBuffer = PNG.sync.write(png, {
90
103
  filterType: pngFilterType,
91
- deflateLevel: pngCompressionLevel,
104
+ deflateLevel: pngCompressionLevel,
92
105
  });
93
106
 
94
107
  if (outputDir) {
@@ -97,9 +110,15 @@ export async function renderMon(monName, mons, reader, rom, options = {}) {
97
110
  await fs.promises.writeFile(fileName, pngBuffer);
98
111
  }
99
112
 
100
- results.push(pngBuffer);
113
+ if (returnFileBuffer) {
114
+ results.push(pngBuffer);
115
+ }
116
+ fullFileCount += 1;
101
117
  }
102
118
  }
103
119
 
104
- return results;
120
+ return {
121
+ ...(returnFileBuffer && { results }),
122
+ fullFileCount,
123
+ }
105
124
  }