|
3 | 3 | const { exec } = require("child_process");
|
4 | 4 | const webpack = require("webpack");
|
5 | 5 | const { cwd } = require("process");
|
6 |
| -const { readFileSync, writeFileSync } = require("fs"); |
| 6 | +const { readFileSync, writeFileSync, createReadStream } = require("fs"); |
| 7 | +const { createHash } = require("crypto"); |
| 8 | + |
| 9 | +const GAME_DATA_COMMAND = |
| 10 | + "npx ts-node --transpile-only --project src/tsconfig.write-game-data.json src/write-game-data.ts"; |
7 | 11 |
|
8 | 12 | const PLUGIN_NAME = "write-tiled-game-data";
|
9 | 13 |
|
10 | 14 | /** Tiled Editor project JSON file */
|
11 | 15 | const PROJECT_FILE = "angular-rpg.tiled-project";
|
12 | 16 |
|
| 17 | +/** Game data is only written when these files change */ |
| 18 | +const SOURCE_FILES = [ |
| 19 | + "./src/app/models/game-data/armors.ts", |
| 20 | + "./src/app/models/game-data/fixed-encounters.ts", |
| 21 | + "./src/app/models/game-data/items.ts", |
| 22 | + "./src/app/models/game-data/magic.ts", |
| 23 | + "./src/app/models/game-data/random-encounters.ts", |
| 24 | + "./src/app/models/game-data/weapons.ts", |
| 25 | +]; |
| 26 | + |
| 27 | +const SEEN_HASHES = {}; |
| 28 | + |
| 29 | +/** Hash the source files used in write-game-data.ts and only run when they change */ |
| 30 | +function shouldWriteData() { |
| 31 | + function checksumFile(filename) { |
| 32 | + return new Promise((resolve, reject) => { |
| 33 | + const hash = createHash("sha1"); |
| 34 | + const stream = createReadStream(filename); |
| 35 | + stream.on("error", (err) => reject(err)); |
| 36 | + stream.on("data", (chunk) => hash.update(chunk)); |
| 37 | + stream.on("end", () => resolve(hash.digest("hex"))); |
| 38 | + }); |
| 39 | + } |
| 40 | + return Promise.all(SOURCE_FILES.map((filename) => checksumFile(filename))).then( |
| 41 | + (hashes) => { |
| 42 | + let should = false; |
| 43 | + SOURCE_FILES.forEach((filename, index) => { |
| 44 | + const hash = hashes[index]; |
| 45 | + if (!SEEN_HASHES[filename]) { |
| 46 | + SEEN_HASHES[filename] = hash; |
| 47 | + should = true; |
| 48 | + } |
| 49 | + if (SEEN_HASHES[filename] !== hash) { |
| 50 | + should = true; |
| 51 | + } |
| 52 | + SEEN_HASHES[filename] = hash; |
| 53 | + }); |
| 54 | + return should; |
| 55 | + } |
| 56 | + ); |
| 57 | +} |
| 58 | + |
13 | 59 | module.exports = class GameDataPlugin {
|
14 | 60 | apply(compiler) {
|
15 |
| - var self = this; |
16 | 61 | compiler.hooks.thisCompilation.tap(PLUGIN_NAME, (compilation) => {
|
17 | 62 | compilation.hooks.processAssets.tapAsync(
|
18 | 63 | {
|
19 | 64 | name: PLUGIN_NAME,
|
20 | 65 | stage: webpack.Compilation.PROCESS_ASSETS_STAGE_ADDITIONAL,
|
21 | 66 | },
|
22 | 67 | (assets, callback) => {
|
23 |
| - console.log("Writing game data files..."); |
24 |
| - console.log("CWD = " + cwd()); |
25 |
| - |
26 |
| - exec( |
27 |
| - "npx ts-node --project src/tsconfig.write-game-data.json src/write-game-data.ts", |
28 |
| - (error, stdout, stderr) => { |
| 68 | + shouldWriteData().then((should) => { |
| 69 | + if (!should) { |
| 70 | + console.log("Skipping Tiled write because source files unchanged"); |
| 71 | + callback(); |
| 72 | + return; |
| 73 | + } |
| 74 | + console.log("Writing Tiled data files"); |
| 75 | + exec(GAME_DATA_COMMAND, (error, stdout, stderr) => { |
29 | 76 | if (error) {
|
30 | 77 | console.log(`error: ${error.message}`);
|
31 | 78 | callback();
|
@@ -68,8 +115,8 @@ module.exports = class GameDataPlugin {
|
68 | 115 | console.log("Writing to: " + PROJECT_FILE);
|
69 | 116 | }
|
70 | 117 | callback();
|
71 |
| - } |
72 |
| - ); |
| 118 | + }); |
| 119 | + }); |
73 | 120 | }
|
74 | 121 | );
|
75 | 122 | });
|
|
0 commit comments