From 4c2df8eede767f0b3c414f4b2717e1a161b38fca Mon Sep 17 00:00:00 2001 From: Matt Klass Date: Sat, 31 Aug 2024 13:39:19 +0000 Subject: [PATCH 1/2] Convert processing code from Javascript to Typescript --- README.md | 16 +- SERVER.md | 2 +- package.json | 4 +- process/package-lock.json | 206 ++++++ process/package.json | 8 +- process/{process.js => process.ts} | 6 +- process/src/{Biome.js => Biome.ts} | 43 +- process/src/{Category.js => Category.ts} | 21 +- process/src/{ChangeLog.js => ChangeLog.ts} | 31 +- ...{ChangeLogCommit.js => ChangeLogCommit.ts} | 103 ++- ...hangeLogVersion.js => ChangeLogVersion.ts} | 43 +- process/src/{Depth.js => Depth.ts} | 21 +- ...{DepthCalculator.js => DepthCalculator.ts} | 27 +- process/src/{GameData.js => GameData.ts} | 150 +++-- process/src/GameObject.js | 326 --------- process/src/GameObject.ts | 616 ++++++++++++++++++ process/src/{Git.js => Git.ts} | 25 +- process/src/MainProcessor.js | 94 --- process/src/MainProcessor.ts | 143 ++++ process/src/ObjectBadges.js | 101 --- process/src/ObjectBadges.ts | 121 ++++ .../{ObjectFilters.js => ObjectFilters.ts} | 81 ++- process/src/{Recipe.js => Recipe.ts} | 31 +- ...{RecipeGenerator.js => RecipeGenerator.ts} | 30 +- process/src/{RecipeNode.js => RecipeNode.ts} | 155 +++-- ...itemapGenerator.js => SitemapGenerator.ts} | 15 +- process/src/Sprite.js | 72 -- process/src/Sprite.ts | 117 ++++ ...{SpriteProcessor.js => SpriteProcessor.ts} | 125 ++-- process/src/{Transition.js => Transition.ts} | 131 ++-- ...itionImporter.js => TransitionImporter.ts} | 104 ++- process/src/readFileNormalized.js | 9 - process/src/readFileNormalized.ts | 9 + process/tsconfig.json | 11 + 34 files changed, 1975 insertions(+), 1022 deletions(-) rename process/{process.js => process.ts} (86%) rename process/src/{Biome.js => Biome.ts} (60%) rename process/src/{Category.js => Category.ts} (78%) rename process/src/{ChangeLog.js => ChangeLog.ts} (68%) rename process/src/{ChangeLogCommit.js => ChangeLogCommit.ts} (63%) rename process/src/{ChangeLogVersion.js => ChangeLogVersion.ts} (54%) rename process/src/{Depth.js => Depth.ts} (77%) rename process/src/{DepthCalculator.js => DepthCalculator.ts} (80%) rename process/src/{GameData.js => GameData.ts} (62%) delete mode 100644 process/src/GameObject.js create mode 100644 process/src/GameObject.ts rename process/src/{Git.js => Git.ts} (79%) delete mode 100644 process/src/MainProcessor.js create mode 100644 process/src/MainProcessor.ts delete mode 100644 process/src/ObjectBadges.js create mode 100644 process/src/ObjectBadges.ts rename process/src/{ObjectFilters.js => ObjectFilters.ts} (70%) rename process/src/{Recipe.js => Recipe.ts} (63%) rename process/src/{RecipeGenerator.js => RecipeGenerator.ts} (80%) rename process/src/{RecipeNode.js => RecipeNode.ts} (79%) rename process/src/{SitemapGenerator.js => SitemapGenerator.ts} (72%) delete mode 100644 process/src/Sprite.js create mode 100644 process/src/Sprite.ts rename process/src/{SpriteProcessor.js => SpriteProcessor.ts} (66%) rename process/src/{Transition.js => Transition.ts} (63%) rename process/src/{TransitionImporter.js => TransitionImporter.ts} (68%) delete mode 100644 process/src/readFileNormalized.js create mode 100644 process/src/readFileNormalized.ts create mode 100644 process/tsconfig.json diff --git a/README.md b/README.md index e857bc2b3..fdf901dd1 100644 --- a/README.md +++ b/README.md @@ -56,16 +56,16 @@ npm install cd .. # run script including downloading latest data and processing sprites -node process download +npm run process -- download # if you want to re-process the sprites without downloading data -node process sprites +npm run process -- sprites # if you want to re-process the sounds without downloading data -node process sounds +npm run process -- sounds # or process without generating sprites -node process +npm run process ``` ### Processing Script (Docker version) @@ -83,16 +83,16 @@ This will build the Docker image used for the build environment, and then set up You can then run different build commands within a container of this image: ``` -./docker-run.sh node process-docker +./docker-run.sh npm run process ``` ``` -./docker-run.sh node process-docker download +./docker-run.sh npm run process -- download ``` ``` -./docker-run.sh node process-docker sprites +./docker-run.sh npm run process -- sprites ``` ``` -./docker-run.sh node process-docker sounds +./docker-run.sh npm run process -- sounds ``` ### Modded Support diff --git a/SERVER.md b/SERVER.md index 1ac1ba753..9169102c1 100644 --- a/SERVER.md +++ b/SERVER.md @@ -81,7 +81,7 @@ Then run it: ``` cd onetech -node process download +npm run process -- download ``` ## Cron diff --git a/package.json b/package.json index 9bbe31d45..f95d42cd8 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,9 @@ "private": true, "scripts": { "dev": "webpack serve", - "build": "webpack --progress" + "build": "webpack --progress", + "process": "cd process && npm run process", + "process-all": "cd process && npm run process -- download" }, "dependencies": { "lodash": "^4.17.21", diff --git a/process/package-lock.json b/process/package-lock.json index ebeda69e3..37803df1a 100644 --- a/process/package-lock.json +++ b/process/package-lock.json @@ -13,6 +13,52 @@ "lodash": "^4.17.21", "node-fetch": "^3.3.2", "sitemap": "^4.1.1" + }, + "devDependencies": { + "@types/canvasjs": "^1.9.11", + "ts-node": "^10.9.2", + "typescript": "^5.5.4" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" } }, "node_modules/@mapbox/node-pre-gyp": { @@ -53,6 +99,41 @@ } } }, + "node_modules/@tsconfig/node10": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/canvasjs": { + "version": "1.9.11", + "resolved": "https://registry.npmjs.org/@types/canvasjs/-/canvasjs-1.9.11.tgz", + "integrity": "sha512-sx1sJS7Y9Hy/jd70Zj23xn2c5LE2tXM3Puh0aQoaMdTeHkbwueeTUeN531sepyujj47UZZGvim85DLiOjpiUeQ==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/node": { "version": "12.20.55", "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz", @@ -71,6 +152,32 @@ "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" }, + "node_modules/acorn": { + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.3", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.3.tgz", + "integrity": "sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/agent-base": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", @@ -166,6 +273,13 @@ "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==" }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true, + "license": "MIT" + }, "node_modules/data-uri-to-buffer": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", @@ -214,6 +328,16 @@ "node": ">=8" } }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -394,6 +518,13 @@ "semver": "bin/semver.js" } }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true, + "license": "ISC" + }, "node_modules/mimic-response": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", @@ -728,11 +859,76 @@ "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/typescript": { + "version": "5.5.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz", + "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true, + "license": "MIT" + }, "node_modules/web-streams-polyfill": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", @@ -780,6 +976,16 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } } } } diff --git a/process/package.json b/process/package.json index 0787c2ba5..e3b4d4134 100644 --- a/process/package.json +++ b/process/package.json @@ -4,7 +4,8 @@ "description": "Processes files from OneHourOneLife into big JSON blobs", "main": "process.js", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "test": "echo \"Error: no test specified\" && exit 1", + "process": "npm i && node_modules/.bin/ts-node process" }, "author": "", "license": "ISC", @@ -13,5 +14,10 @@ "lodash": "^4.17.21", "node-fetch": "^3.3.2", "sitemap": "^4.1.1" + }, + "devDependencies": { + "@types/canvasjs": "^1.9.11", + "ts-node": "^10.9.2", + "typescript": "^5.5.4" } } diff --git a/process/process.js b/process/process.ts similarity index 86% rename from process/process.js rename to process/process.ts index 154f99702..770f3cf7e 100644 --- a/process/process.js +++ b/process/process.ts @@ -1,8 +1,10 @@ + + if (!process.env.ONETECH_FOOD_BONUS) { - process.env.ONETECH_FOOD_BONUS = 0; + process.env.ONETECH_FOOD_BONUS = '0'; } -const MainProcessor = require('./src/MainProcessor'); +import {MainProcessor} from './src/MainProcessor'; const processor = new MainProcessor(__dirname); diff --git a/process/src/Biome.js b/process/src/Biome.ts similarity index 60% rename from process/src/Biome.js rename to process/src/Biome.ts index 4d4d8980d..77e0ebccf 100644 --- a/process/src/Biome.js +++ b/process/src/Biome.ts @@ -1,13 +1,19 @@ "use strict"; +import { GameObject } from "./GameObject"; + class Biome { - static fromFilename(filename) { + id: string; + groundHeat: number; + objects: GameObject[]; + + static fromFilename(filename: string): Biome { const id = filename.replace("ground_", "").replace(".tga", ""); if (!id || id === "U") return; return new Biome(id); } - static applyGroundHeat(biomes, filename, content) { + static applyGroundHeat(biomes: Biome[], filename: string, content: string): void { const id = filename.replace("groundHeat_", "").replace(".txt", ""); if (!id || id === "U") return; const biome = biomes.find(b => b.id === id); @@ -15,18 +21,18 @@ class Biome { biome.groundHeat = parseFloat(content); } - constructor(id) { + constructor(id: string) { this.id = id; - this.groundHeat = 0; + this.groundHeat = 0.0; this.objects = []; } - name() { + name(): string { const names = ["Grasslands", "Swamps", "Yellow Prairies", "Badlands", "Tundra", "Desert", "Jungle", "Deep Water", "Flower Fields", "Shallow Water"]; - return names[this.id]; + return names[parseInt(this.id)]; } - addObjects(objects) { + addObjects(objects: GameObject[]) { for (let object of objects) { if (object.data.biomes && object.data.biomes.includes(parseInt(this.id))) { this.objects.push(object); @@ -35,21 +41,22 @@ class Biome { } } - totalMapChance() { + totalMapChance(): number { return this.objects.map(o => o.data.mapChance).reduce((a,b) => a + b); } - spawnChance(object) { + spawnChance(object: GameObject): number { const total = this.totalMapChance(); if (!total) return 0; return object.data.mapChance / total; } - jsonData() { - const result = { + jsonData(): ExportedBiomeData { + const result: ExportedBiomeData = { id: this.id, groundHeat: this.groundHeat, name: this.name(), + objects: [], }; result.objects = this.objects.map(object => { return {id: object.id, spawnChance: this.spawnChance(object)}; @@ -58,4 +65,16 @@ class Biome { } } -module.exports = Biome; +interface ExportedBiomeObjectData { + id: string; + spawnChance: number; +} + +interface ExportedBiomeData { + id: string; + groundHeat: number; + name: string; + objects: ExportedBiomeObjectData[]; +} + +export { Biome, ExportedBiomeData, ExportedBiomeObjectData } diff --git a/process/src/Category.js b/process/src/Category.ts similarity index 78% rename from process/src/Category.js rename to process/src/Category.ts index 68b6ef48d..cad45c5fe 100644 --- a/process/src/Category.js +++ b/process/src/Category.ts @@ -1,7 +1,16 @@ "use strict"; +import { GameObject } from "./GameObject"; + class Category { - constructor(dataText) { + objectIDs: string[]; + objectWeights: number[]; + parentID: string; + pattern: boolean; + probSet: boolean; + parent: GameObject; + objects: GameObject[]; + constructor(dataText: string) { this.objectIDs = []; this.objectWeights = []; const lines = dataText.split('\n'); @@ -15,7 +24,7 @@ class Category { } } - processHeader(line) { + processHeader(line: string): boolean { const parts = line.split('='); switch (parts[0]) { case "parentID": this.parentID = parts[1]; break; @@ -27,7 +36,7 @@ class Category { return true; // Continue processing headers } - processObject(line) { + processObject(line: string): void { const parts = line.split(' '); if (parts[0]) { this.objectIDs.push(parts[0]); @@ -37,11 +46,11 @@ class Category { } } - objectWeight(id) { + objectWeight(id: string): number { return this.objectWeights[this.objectIDs.indexOf(id)]; } - addToObjects(objects) { + addToObjects(objects: Record): void { this.parent = objects[this.parentID]; if (!this.parent) throw "Unable to find object with id " + this.parentID; this.parent.category = this; @@ -60,4 +69,4 @@ class Category { } } -module.exports = Category; +export { Category } diff --git a/process/src/ChangeLog.js b/process/src/ChangeLog.ts similarity index 68% rename from process/src/ChangeLog.js rename to process/src/ChangeLog.ts index 723eac681..5549292e8 100644 --- a/process/src/ChangeLog.js +++ b/process/src/ChangeLog.ts @@ -1,22 +1,27 @@ "use strict"; -const Git = require('./Git'); -const ChangeLogVersion = require('./ChangeLogVersion'); +import { Git } from "./Git"; +import { ChangeLogVersion } from "./ChangeLogVersion"; +import { GameObject } from "./GameObject"; class ChangeLog { - constructor(gitDir, objects, releasedOnly) { + git: Git; + objects: Record; + versions: ChangeLogVersion[]; + + constructor(gitDir: string, objects: Record, releasedOnly: boolean) { this.git = new Git(gitDir); this.objects = objects; this.versions = this.fetchVersions(releasedOnly); } - fetchVersions(releasedOnly) { - let previousVersion = null; + fetchVersions(releasedOnly: boolean): ChangeLogVersion[] { + let previousVersion: ChangeLogVersion = null; const versions = this.fetchVersionNumbers().map(id => { const version = new ChangeLogVersion( this.git, this.objects, - id, + id.toString(), previousVersion ); previousVersion = version; @@ -33,17 +38,17 @@ class ChangeLog { return versions; } - fetchVersionNumbers() { + fetchVersionNumbers(): number[] { return this.git.tags().map(t => this.versionNumberFromTag(t)).filter(t => !isNaN(t)).sort((a,b) => a - b); } - versionNumberFromTag(tag) { + versionNumberFromTag(tag: string): number { const version = tag.replace(/OneLife_v|2HOL_v/, ""); if (version == "Start") return 0; return parseInt(version); } - populateObjects() { + populateObjects(): void { for (let version of this.versions) { if (version.isReleased()) { version.populateObjects(); @@ -53,16 +58,16 @@ class ChangeLog { this.reportMissing(); } - validVersions() { + validVersions(): ChangeLogVersion[] { return this.versions.slice(1).reverse(); } - lastReleasedVersion() { + lastReleasedVersion(): ChangeLogVersion { const versions = this.versions.filter(v => v.isReleased()); return versions[versions.length-1]; } - reportMissing() { + reportMissing(): void { const objects = Object.values(this.objects).filter(o => !o.version); console.log(objects.length + " objects are missing version"); // for (let object of objects) { @@ -71,4 +76,4 @@ class ChangeLog { } } -module.exports = ChangeLog; +export { ChangeLog } diff --git a/process/src/ChangeLogCommit.js b/process/src/ChangeLogCommit.ts similarity index 63% rename from process/src/ChangeLogCommit.js rename to process/src/ChangeLogCommit.ts index 5bc7c45b9..34245560f 100644 --- a/process/src/ChangeLogCommit.js +++ b/process/src/ChangeLogCommit.ts @@ -1,10 +1,36 @@ "use strict"; -const GameObject = require('./GameObject'); -const Transition = require('./Transition'); +import { ChangeLogVersion } from "./ChangeLogVersion"; +import { GameObject } from "./GameObject"; +import { ChangeLogEntry, Git } from "./Git"; +import { ExportedTransitionData, Transition } from "./Transition"; + +interface ObjectChange { + id: string, + attributes: Record, +} + +interface LegacyObjectData { + id: string, + name: string, + category: boolean, +} class ChangeLogCommit { - constructor(version, log) { + version: ChangeLogVersion; + git: Git; + objects: Record; + legacyObjects: Record; + sha: string; + date: Date; + message: string; + addedObjects: GameObject[]; + removedObjects: GameObject[]; + addedTransitions: Transition[]; + removedTransitions: Transition[]; + objectChanges: ObjectChange[]; + + constructor(version: ChangeLogVersion, log: ChangeLogEntry) { this.version = version; this.git = version.git; this.objects = version.objects; @@ -20,7 +46,7 @@ class ChangeLogCommit { this.parseChanges(); } - isRelavent() { + isRelevant(): boolean { if (this.message.includes("dataVersionNumber")) return false; if (this.message.startsWith("Merge branch")) @@ -30,7 +56,7 @@ class ChangeLogCommit { return true } - parseChanges() { + parseChanges(): void { const changes = this.git.fileChanges(this.sha + "^", this.sha); for (let change of changes) { if (change[1].startsWith("objects")) @@ -40,7 +66,7 @@ class ChangeLogCommit { } } - parseObjectChange(path, mode) { + parseObjectChange(path: string, mode: string): void { const id = path.split("/")[1].split(".")[0]; if (mode == "A") { const object = this.lookupObject(path, mode); @@ -55,7 +81,7 @@ class ChangeLogCommit { } } - parseTransitionChange(path, mode) { + parseTransitionChange(path: string, mode: string): void { if (mode == "A") { const transition = this.createTransition(path, mode); this.addedTransitions.push(transition); @@ -72,7 +98,7 @@ class ChangeLogCommit { } } - isSignificantChange(oldTransition, newTransition) { + isSignificantChange(oldTransition: Transition, newTransition: Transition): boolean { if (oldTransition.actorID != newTransition.actorID) return true; if (oldTransition.targetID != newTransition.targetID) @@ -86,7 +112,7 @@ class ChangeLogCommit { return false; } - lookupObject(path, mode) { + lookupObject(path: string, mode: string): GameObject { const id = path.split("/")[1].split(".")[0]; if (this.objects[id]) { @@ -107,7 +133,7 @@ class ChangeLogCommit { return object; } - createTransition(path, mode) { + createTransition(path: string, mode: string): Transition { const content = this.fileContent(path, mode); const filename = path.split("/")[1]; const transition = new Transition(content, filename); @@ -118,14 +144,21 @@ class ChangeLogCommit { return transition; } - setTransitionObject(transition, key, mode) { - const id = transition[key + "ID"]; - if (id > 1) { + setTransitionObject(transition: Transition, key: string, mode: string): void { + let id: string; + switch (key) { + case "actor": id = transition.actorID; break; + case "target": id = transition.targetID; break; + case "newActor": id = transition.newActorID; break; + case "newTarget": id = transition.newTargetID; break; + default: console.log("Unknown transition object key: " + key); return; + } + if (parseInt(id) > 1) { transition[key] = this.lookupObject(`objects/${id}.txt`, mode) } } - addObjectChange(path) { + addObjectChange(path: string): void { const before = new GameObject(this.git.fileContent(`${this.sha}^`, path)); const after = new GameObject(this.git.fileContent(this.sha, path)); const change = this.objectChange(before, after); @@ -133,7 +166,7 @@ class ChangeLogCommit { this.objectChanges.push(this.objectChange(before, after)); } - ignoredAttributes() { + ignoredAttributes(): string[] { return [ "slotPos", "pixHeight", @@ -150,16 +183,19 @@ class ChangeLogCommit { ]; } - objectChange(before, after) { + objectChange(before: GameObject, after: GameObject): ObjectChange { const ignore = this.ignoredAttributes(); - const attributes = {}; + const attributes: Record = {}; for (let attribute in after.data) { if (ignore.includes(attribute)) continue; - if (typeof before.data[attribute] == 'undefined') + if (!Object.getOwnPropertyNames(before).includes(attribute)) continue; - if (String(before.data[attribute]) != String(after.data[attribute])) { - attributes[attribute] = {from: before.data[attribute], to: after.data[attribute]}; + if (String(before.data[attribute as keyof typeof before.data]) !== String(after.data[attribute as keyof typeof after.data])) { + attributes[attribute] = { + from: before.data[attribute as keyof typeof before.data], + to: after.data[attribute as keyof typeof after.data] + }; } } if (Object.keys(attributes).length == 0) @@ -167,13 +203,13 @@ class ChangeLogCommit { return {id: after.id, attributes: attributes}; } - fileContent(path, mode) { + fileContent(path: string, mode: string): string { const sha = (mode == "D" ? `${this.sha}^` : this.sha); return this.git.fileContent(sha, path); } - jsonData() { - const data = {sha: this.sha, message: this.message, date: this.date}; + jsonData(): ExportedChangeLogCommitData { + const data: ExportedChangeLogCommitData = {sha: this.sha, message: this.message, date: this.date}; if (this.addedObjects.length) data.addedObjectIDs = this.addedObjects.map(o => o.id); @@ -196,16 +232,29 @@ class ChangeLogCommit { return data; } - filterTransitions(transitions) { + filterTransitions(transitions: Transition[]): Transition[] { let ids = this.addedObjects.map(o => o.id); ids = ids.concat(Object.keys(this.legacyObjects)); ids = ids.concat(this.removedObjects.map(o => o.id)); return transitions.filter(t => !ids.includes(t.actorID) && !ids.includes(t.targetID)); } - legacyObjectData(object) { - return {id: object.id, name: object.name, category: !!object.isCategory()}; + legacyObjectData(object: GameObject): LegacyObjectData { + return {id: object.id, name: object.name, category: object.isCategory()}; } } -module.exports = ChangeLogCommit; +interface ExportedChangeLogCommitData { + sha: string; + message: string; + date: Date; + addedObjectIDs?: string[]; + removedObjectIDs?: string[]; + // TODO: Change this to ExportedTransitionData when it gets defined. + addedTransitions?: ExportedTransitionData[]; + removedTransitions?: ExportedTransitionData[]; + objectChanges?: ObjectChange[]; + legacyObjects?: LegacyObjectData[]; +} + +export { ChangeLogCommit, ExportedChangeLogCommitData } diff --git a/process/src/ChangeLogVersion.js b/process/src/ChangeLogVersion.ts similarity index 54% rename from process/src/ChangeLogVersion.js rename to process/src/ChangeLogVersion.ts index 3ce1122c0..0541f543c 100644 --- a/process/src/ChangeLogVersion.js +++ b/process/src/ChangeLogVersion.ts @@ -1,23 +1,30 @@ "use strict"; -const ChangeLogCommit = require('./ChangeLogCommit'); +import { ChangeLogCommit, ExportedChangeLogCommitData } from "./ChangeLogCommit"; +import { GameObject } from "./GameObject"; +import { Git } from "./Git"; class ChangeLogVersion { - constructor(git, objects, id, previous) { + git: Git; + objects: Record; + id: string; + previous: ChangeLogVersion; + commits: ChangeLogCommit[]; + constructor(git: Git, objects: Record, id: string, previous: ChangeLogVersion) { this.git = git; this.objects = objects; this.id = id; this.previous = previous; } - tag() { - if (this.id == 0) return "OneLife_vStart"; + tag(): string { + if (this.id == '0') return "OneLife_vStart"; if (this.isUnreleased()) return "master"; - if (this.id < 20269) return "OneLife_v" + this.id; + if (parseInt(this.id) < 20269) return "OneLife_v" + this.id; return "2HOL_v" + this.id; } - populateObjects() { + populateObjects(): void { const differences = this.diff(); for (let difference of differences) { if (difference[0] == "A") @@ -27,12 +34,12 @@ class ChangeLogVersion { } } - diff() { + diff(): string[][] { if (!this.previous) return []; return this.git.fileChanges(this.previous.tag(), this.tag()); } - populateObjectAtPath(path) { + populateObjectAtPath(path: string): void { const parts = path.split("/"); if (parts[0] == "objects") { const object = this.objects[parts[1].split(".")[0]]; @@ -41,17 +48,17 @@ class ChangeLogVersion { } } - jsonData() { - const data = {id: this.id}; + jsonData(): ExportedChangeLogVersionData { + const data: ExportedChangeLogVersionData = {id: this.id}; const commits = this.fetchCommits(); if (this.isReleased() && commits[0]) { data.date = commits[0].date; } - data.commits = commits.filter(c => c.isRelavent()).map(c => c.jsonData()); + data.commits = commits.filter(c => c.isRelevant()).map(c => c.jsonData()); return data; } - fetchCommits() { + fetchCommits(): ChangeLogCommit[] { if (!this.previous) return []; if (!this.commits) { this.commits = this.git.log(this.previous.tag(), this.tag()).map(entry => { @@ -61,13 +68,19 @@ class ChangeLogVersion { return this.commits; } - isUnreleased() { + isUnreleased(): boolean { return this.id === "unreleased"; } - isReleased() { + isReleased(): boolean { return this.id !== "unreleased"; } } -module.exports = ChangeLogVersion; +interface ExportedChangeLogVersionData { + id: string; + date?: Date; + commits?: ExportedChangeLogCommitData[]; +} + +export { ChangeLogVersion, ExportedChangeLogVersionData } diff --git a/process/src/Depth.js b/process/src/Depth.ts similarity index 77% rename from process/src/Depth.js rename to process/src/Depth.ts index 5280fe8fd..0e60404fb 100644 --- a/process/src/Depth.js +++ b/process/src/Depth.ts @@ -1,16 +1,23 @@ "use strict"; +import { GameObject } from "./GameObject"; +import { Transition } from "./Transition"; + // Depth is the deepest number of steps needed to craft an object // Natural and uncraftable objects have a depth of 0 class Depth { - constructor({ value, difficulty, craftable }) { + calculated: boolean; + value: number; + difficulty: number; + craftable: boolean; + constructor({ value = null, difficulty = 0, craftable }: {value?: number, difficulty?: number, craftable: boolean}) { this.calculated = !isNaN(value); this.value = value || 0; - this.difficulty = difficulty || 0; + this.difficulty = difficulty; this.craftable = craftable; } - addTransition(transition) { + addTransition(transition: Transition): void { this.addObject(transition.actor); this.addObject(transition.target); this.value++; @@ -24,7 +31,7 @@ class Depth { this.difficulty += 4; } - addObject(object) { + addObject(object: GameObject): void { if (!object) return; this.calculated = this.calculated && object.depth.calculated; this.craftable = this.craftable && object.depth.craftable; @@ -32,7 +39,7 @@ class Depth { this.difficulty += object.depth.difficulty; } - clone() { + clone(): Depth { return new Depth({ value: this.value, difficulty: this.difficulty, @@ -41,7 +48,7 @@ class Depth { } // Sorts based on priority: calculated, craftable, value, difficulty - compare(depth) { + compare(depth: Depth): number { if (this.calculated == depth.calculated) { if (this.craftable == depth.craftable) { if (this.value == depth.value) { @@ -63,4 +70,4 @@ class Depth { } } -module.exports = Depth; +export { Depth } diff --git a/process/src/DepthCalculator.js b/process/src/DepthCalculator.ts similarity index 80% rename from process/src/DepthCalculator.js rename to process/src/DepthCalculator.ts index 4ddbc3440..6de060c36 100644 --- a/process/src/DepthCalculator.js +++ b/process/src/DepthCalculator.ts @@ -1,13 +1,16 @@ "use strict"; -const Depth = require('./Depth'); +import { Depth } from "./Depth"; +import { GameObject } from "./GameObject"; +import { Transition } from "./Transition"; class DepthCalculator { - constructor(objects) { + objects: GameObject[]; + constructor(objects: GameObject[]) { this.objects = objects; } - calculate() { + calculate(): void { this.calculateDepth(); this.sortObjectTransitions(); this.calculateDifficulty(); @@ -15,17 +18,17 @@ class DepthCalculator { } // Calculates the depth starting with natural and uncraftable objects. - calculateDepth() { + calculateDepth(): void { for (let object of this.objects) { if (object.isNatural() || object.transitionsToward.length === 0) { - this.setObjectDepth(object, new Depth({value: 0, craftable: object.isNatural()})); + this.setObjectDepth(object, new Depth({value: 0, craftable: object.isNatural(), difficulty: 0})); } } } // Sets the object depth if it is lower than previously set // It then calculates the depth for each "away" transition - setObjectDepth(object, depth) { + setObjectDepth(object: GameObject, depth: Depth): void { if (depth.compare(object.depth) < 0) { // console.log("Depth set for", object.id, object.name, "to", depth.value); object.depth = depth; @@ -42,9 +45,9 @@ class DepthCalculator { // Calculates the transition depth by finding max of actor and target depths // If the depth was calculated, it sets it to the resulting object - calculateTransition(transition) { + calculateTransition(transition: Transition): void { // Start in true state so adding transition can make to uncraftable - const depth = new Depth({value: 0, craftable: true}); + const depth = new Depth({value: 0, craftable: true, difficulty: 0}); depth.addTransition(transition); transition.depth = depth; @@ -56,21 +59,21 @@ class DepthCalculator { this.setObjectDepth(transition.newExtraTarget, depth); } - sortObjectTransitions() { + sortObjectTransitions(): void { for (let object of this.objects) { object.transitionsToward.sort((a,b) => a.depth.compare(b.depth)); object.transitionsAway.sort((a,b) => a.depth.compare(b.depth)); } } - calculateDifficulty() { + calculateDifficulty(): void { const depths = this.objects.map(o => o.depth).filter(c => c.difficulty > 0).sort((a,b) => a.difficulty - b.difficulty); for (let i in depths) { depths[i].difficulty = parseFloat(i) / depths.length; } } - reportUncraftable() { + reportUncraftable(): void { const objects = this.objects.filter(o => !o.depth.craftable && o.isVisible()); console.log(objects.length + " objects are uncraftable"); // for (let object of objects) { @@ -79,4 +82,4 @@ class DepthCalculator { } } -module.exports = DepthCalculator; +export { DepthCalculator } diff --git a/process/src/GameData.js b/process/src/GameData.ts similarity index 62% rename from process/src/GameData.js rename to process/src/GameData.ts index 02469e69b..dc6f1a422 100644 --- a/process/src/GameData.js +++ b/process/src/GameData.ts @@ -1,32 +1,45 @@ "use strict"; -const { spawnSync } = require('child_process'); -const fs = require('fs'); +import { spawnSync } from 'child_process'; +import * as fs from 'fs'; const _ = require('lodash'); -const GameObject = require('./GameObject'); -const Category = require('./Category'); -const TransitionImporter = require('./TransitionImporter'); -const ChangeLog = require('./ChangeLog'); -const Biome = require('./Biome'); -const DepthCalculator = require('./DepthCalculator'); -const SpriteProcessor = require('./SpriteProcessor'); -const ObjectFilters = require('./ObjectFilters'); -const ObjectBadges = require('./ObjectBadges'); -const SitemapGenerator = require('./SitemapGenerator'); -const readFileNormalized = require('./readFileNormalized'); +import { GameObject } from "./GameObject"; +import { Category } from "./Category"; +import { TransitionImporter } from "./TransitionImporter"; +import { ChangeLog } from "./ChangeLog"; +import { Biome } from "./Biome"; +import { DepthCalculator } from "./DepthCalculator"; +import { SpriteProcessor } from "./SpriteProcessor"; +import { ExportedObjectFilterData, ObjectFilters } from "./ObjectFilters"; +import { ExportedObjectBadgesData, ObjectBadges } from "./ObjectBadges"; +import { SitemapGenerator } from "./SitemapGenerator"; +import { readFileNormalized } from "./readFileNormalized"; +import { ChangeLogVersion } from './ChangeLogVersion'; class GameData { - constructor(processDir, dataDir, staticDir) { + processDir: string; + dataDir: string; + staticDir: string; + objects: Record; + categories: Category[]; + biomes: Biome[]; + releasedOnly: boolean; + badges: ObjectBadges; + filters: ObjectFilters; + changeLog: ChangeLog; + constructor(processDir: string, dataDir: string, staticDir: string) { this.processDir = processDir; this.dataDir = dataDir; this.staticDir = staticDir; this.objects = {}; this.categories = []; this.biomes = []; + this.badges = new ObjectBadges(); + this.filters = new ObjectFilters(); } - download(gitURL) { + download(gitURL: string): void { if (fs.existsSync(this.dataDir)) { this.checkoutMaster(); spawnSync("git", ["pull"], {cwd: this.dataDir}); @@ -35,22 +48,22 @@ class GameData { } } - verifyDownloaded() { + verifyDownloaded(): void { if (!fs.existsSync(this.dataDir)) { throw "OneLifeData7 not found, first run `node process dev download`" } } - checkoutVersion(version) { + checkoutVersion(version: ChangeLogVersion): void { this.releasedOnly = true; spawnSync("git", ["checkout", version.tag()], {cwd: this.dataDir}); } - checkoutMaster() { + checkoutMaster(): void { spawnSync("git", ["checkout", "master"], {cwd: this.dataDir}); } - importObjects() { + importObjects(): void { this.eachFileContent("objects", ".txt", (content, _filename) => { const object = new GameObject(content); if (object.id) { @@ -60,7 +73,7 @@ class GameData { console.log("Object Count: " + Object.values(this.objects).length); } - importCategories() { + importCategories(): void { this.eachFileContent("categories", ".txt", (content, _filename) => { const category = new Category(content); category.addToObjects(this.objects); @@ -69,7 +82,7 @@ class GameData { console.log("Category Count: " + this.categories.length); } - importTransitions() { + importTransitions(): void { const importer = new TransitionImporter(); this.eachFileContent("transitions", ".txt", (content, filename) => { importer.importFromFile(content, filename); @@ -82,7 +95,7 @@ class GameData { console.log("Transition Count: " + importer.transitions.length); } - importBiomes() { + importBiomes(): void { this.eachFileInDir("ground", ".tga", (_path, filename) => { const biome = Biome.fromFilename(filename); if (biome) { @@ -102,45 +115,50 @@ class GameData { console.log("Biome Count: " + this.biomes.length); } - populateVersions() { + populateVersions(): void { this.changeLog = new ChangeLog(this.dataDir, this.objects, this.releasedOnly); this.changeLog.populateObjects(); } - calculateObjectDepth() { - var calculator = new DepthCalculator(Object.values(this.objects)); + calculateObjectDepth(): void { + let calculator = new DepthCalculator(Object.values(this.objects)); calculator.calculate(); } - generateTechTree() { - var generator = new TechTreeGenerator(); - generator.generate(Object.values(this.objects)); - } + // generateTechTree() { + // var generator = new TechTreeGenerator(); + // generator.generate(Object.values(this.objects)); + // } - exportObjects() { - this.saveJSON("objects.json", this.objectsData()); + exportObjects(): void { + this.populateFilters(); + this.saveJSON("objects.json", this.objectsJsonData()); for (let id in this.objects) { this.saveJSON(`objects/${id}.json`, this.objects[id].jsonData()); } } - exportVersions() { + populateFilters(): void { + this.filters.setupFilters(Object.values(this.objects)); + } + + exportVersions(): void { const versions = this.changeLog.versions.slice().reverse(); for (let version of versions) { const path = `versions/${version.id}.json`; - if (version.isUnreleased() || version.id > 0 && !fs.existsSync(this.staticDir + "/" + path)) { + if (version.isUnreleased() || parseInt(version.id) > 0 && !fs.existsSync(this.staticDir + "/" + path)) { this.saveJSON(path, version.jsonData()); } } } - exportBiomes() { + exportBiomes(): void { for (let biome of this.biomes) { this.saveJSON(`biomes/${biome.id}.json`, biome.jsonData()); } } - prepareStaticDir() { + prepareStaticDir(): void { this.makeDir(this.staticDir); this.makeDir(this.staticDir + "/sprites"); this.makeDir(this.staticDir + "/ground"); @@ -154,22 +172,23 @@ class GameData { this.makeDir(this.staticDir + "/pretty-json/biomes"); } - makeDir(path) { + makeDir(path: string): void { if (!fs.existsSync(path)) fs.mkdirSync(path); } - saveJSON(path, data) { + // Allow any so we can save any object/array/value we want + saveJSON(path: string, data: any): void { const minPath = this.staticDir + "/" + path; const prettyPath = this.staticDir + "/pretty-json/" + path; fs.writeFileSync(minPath, JSON.stringify(data)); fs.writeFileSync(prettyPath, JSON.stringify(data, null, 2)); } - objectsData() { - var objects = _.sortBy(this.objects, o => o.sortWeight()).filter(o => o.isVisible()); + objectsJsonData(): ExportedObjectsData { + var objects = _.sortBy(this.objects, (o: GameObject) => o.sortWeight()).filter((o: GameObject) => o.isVisible()); // Traverse objects array only once, pushing to each array the part it needs. let objectsData = objects.reduce( - (acc, o) => { + (acc: { ids: string[]; names: string[]; difficulties: string[]; numSlots: number[]; craftable: boolean[]; }, o: GameObject) => { acc.ids.push(o.id); acc.names.push(o.name); acc.difficulties.push(o.difficulty()); @@ -185,19 +204,19 @@ class GameData { difficulties: objectsData.difficulties, numSlots: objectsData.numSlots, craftable: objectsData.craftable, - filters: ObjectFilters.jsonData(objects), - badges: ObjectBadges.jsonData(objects), + filters: this.filters.jsonData(), + badges: this.badges.jsonData(objects), date: new Date(), versions: this.changeLog.validVersions().map(v => v.id), biomeIds: this.biomes.map(b => b.id), biomeNames: this.biomes.map(b => b.name()), - foodEatBonus: parseInt(process.env.ONETECH_FOOD_BONUS), + foodEatBonus: parseInt(process.env.ONETECH_FOOD_BONUS || '0'), }; } - convertSpriteImages() { + convertSpriteImages(): void { const dir = this.dataDir + "/sprites"; - for (var filename of fs.readdirSync(dir)) { + for (let filename of fs.readdirSync(dir)) { if (filename.endsWith(".tga")) { const id = filename.split('.')[0]; const inPath = dir + "/" + filename; @@ -207,9 +226,9 @@ class GameData { } } - convertGroundImages() { + convertGroundImages(): void { const dir = this.dataDir + "/ground"; - for (var filename of fs.readdirSync(dir)) { + for (let filename of fs.readdirSync(dir)) { if (filename.endsWith(".tga")) { const name = filename.split('.')[0]; const inPath = dir + "/" + filename; @@ -219,9 +238,9 @@ class GameData { } } - convertSounds() { + convertSounds(): void { const dir = this.dataDir + "/sounds"; - for (var filename of fs.readdirSync(dir)) { + for (let filename of fs.readdirSync(dir)) { if (filename.endsWith(".aiff")) { const id = filename.split('.')[0]; const inPath = dir + "/" + filename; @@ -232,12 +251,12 @@ class GameData { } } - processSprites() { + processSprites(): void { const processor = new SpriteProcessor(this.dataDir + "/sprites", this.staticDir + "/sprites") processor.process(this.objects) } - eachFileInDir(dirName, extension, callback) { + eachFileInDir(dirName: string, extension: string, callback: (fileWithPath: string, file: string) => void): void { const dir = this.dataDir + "/" + dirName; for (let filename of fs.readdirSync(dir)) { if (filename.endsWith(extension)) { @@ -246,18 +265,18 @@ class GameData { } } - eachFileContent(dirName, extension, callback) { + eachFileContent(dirName: string, extension: string, callback: (fileContent: string, filename: string) => void): void { this.eachFileInDir(dirName, extension, (path, filename) => { - callback(readFileNormalized(path, "utf8"), filename); + callback(readFileNormalized(path), filename); }); } - generateSitemap() { - var generator = new SitemapGenerator(this.processDir + "/../"); - generator.generate(Object.values(this.objects), this.biomes); + generateSitemap(): void { + let generator = new SitemapGenerator(this.processDir + "/../"); + generator.generate(Object.values(this.objects), this.filters.filters, this.biomes); } - unprocessedVersion(staticDir, force) { + unprocessedVersion(staticDir: string, force: boolean): ChangeLogVersion { const version = this.changeLog.lastReleasedVersion(); const path = `versions/${version.id}.json`; if (force || !fs.existsSync(staticDir + "/" + path)) { @@ -266,4 +285,19 @@ class GameData { } } -module.exports = GameData; +interface ExportedObjectsData { + ids: string[], + names: string[], + difficulties: string[], + numSlots: number[], + craftable: boolean[], + filters: ExportedObjectFilterData, + badges: ExportedObjectBadgesData, + date: Date, + versions: string[], + biomeIds: string[], + biomeNames: string[], + foodEatBonus: number, +} + +export { GameData } diff --git a/process/src/GameObject.js b/process/src/GameObject.js deleted file mode 100644 index fc1523c65..000000000 --- a/process/src/GameObject.js +++ /dev/null @@ -1,326 +0,0 @@ -"use strict"; - -const Sprite = require('./Sprite'); -const Depth = require('./Depth'); -const Recipe = require('./Recipe'); - -class GameObject { - constructor(dataText) { - this.data = {}; - this.sprites = []; - this.transitionsToward = []; - this.transitionsAway = []; - this.categories = []; - this.biomes = []; - this.depth = new Depth({}); - this.parseData(dataText); - if (!this.data.id) - return; - this.id = this.data.id.toString(); - this.name = this.data.name; - } - - parseData(dataText) { - const lines = dataText.split('\n'); - for (var i = 0; i < lines.length; i++) { - if (i == 1) { - this.parseName(lines[i]); - } else if (lines[i].includes('spriteID')) { - this.parseSprite(lines.slice(i, i+8)); - i += 7; - } else { - this.parseLine(lines[i]); - } - } - } - - parseName(name) { - if (name) - this.data.name = name.replace(/#/g, ' - '); - } - - parseLine(line) { - const assignments = line.split(/[,#]/); - let attribute = null; - let values = []; - for (let assignment of assignments) { - const parts = assignment.split(/[_=]/); - if (parts.length > 1) { - this.assignData(attribute, values); - attribute = parts.shift(); - values = []; - } - values.push(this.parseValue(parts[0])); - } - this.assignData(attribute, values); - } - - parseValue(value) { - if (isNaN(value)) - return value; - if (value.includes(".")) - return parseFloat(value); - return parseInt(value); - } - - assignData(attribute, values) { - if (!attribute) return; - if (attribute == "numUses") { - this.data.numUses = values[0]; - this.data.useChance = parseFloat(values[1] || 1.0); - } else if (attribute == "foodValue") { - if (values.length == 1) values.push(0); - this.data.foodValue = values; - } else if (attribute == "biomes" || attribute == "useAppearIndex" || attribute == "spritesAdditiveBlend") { - this.data[attribute] = values; - } else if (values.length == 1) { - this.data[attribute] = values[0]; - } else { - this.data[attribute] = values; - } - } - - parseSprite(lines) { - this.sprites.push(new Sprite(lines, this.sprites.length, this)); - } - - jsonData() { - const transitionsToward = this.transitionsToward; - const transitionsAway = this.transitionsAway.filter(t => !t.decay); - const transitionsTimed = this.transitionsAway.filter(t => t.decay); - const result = { - id: this.id, - name: this.name, - transitionsToward: transitionsToward.map(t => t.jsonData()), - transitionsAway: transitionsAway.map(t => t.jsonData()), - transitionsTimed: transitionsTimed.map(t => t.jsonData()), - }; - - if (this.version) { - result.version = this.version; - } - - if (this.data.foodValue[0] > 0) { - result.foodValue = this.data.foodValue; - } - - if (this.data.heatValue > 0) { - result.heatValue = this.data.heatValue; - } - - if (this.data.numUses > 1) { - result.numUses = this.data.numUses; - if (this.data.useChance != 1) - result.useChance = this.data.useChance; - } - - result.craftable = this.depth.craftable; - if (this.depth.craftable) { - result.depth = this.depth.value; - } - - if (this.data.clothing != "n") { - result.clothing = this.data.clothing; - result.insulation = this.insulation(); - } else if (this.data.rValue > 0 && (this.data.floor == 1 || this.data.blocksWalking == 1)) { - result.insulation = this.data.rValue; - } - - if (this.isDeadly()) { - result.deadlyDistance = this.data.deadlyDistance; - } - - if (this.data.useDistance > 1 && this.data.deadlyDistance > 1) { - result.useDistance = this.data.useDistance; - } - - if (this.data.mapChance > 0) { - result.mapChance = this.data.mapChance; - result.biomes = this.biomesData(); - } - - if (this.data.numSlots > 0) { - result.numSlots = this.data.numSlots; - result.slotSize = this.data.slotSize; - } - - if (this.data.containable == 1) { - result.size = this.data.containSize; - } - - if (this.canPickup()) { - result.minPickupAge = parseInt(this.data.minPickupAge) || 3; - } - - if (this.data.speedMult != 1) { - result.speedMult = parseFloat(this.data.speedMult); - } - - if (this.data.blocksWalking == 1) { - result.blocksWalking = true; - } - - const sounds = this.sounds(); - if (sounds.length > 0) { - result.sounds = sounds; - } - - const moveTransition = this.transitionsAway.find(t => t.move > 0); - if (moveTransition) { - result.moveType = moveTransition.move; - result.moveDistance = moveTransition.desiredMoveDist; - } - - const techTree = this.techTreeNodes(3); - if (techTree) { - result.techTree = techTree; - } - - const recipe = new Recipe(this); - recipe.generate(); - if (recipe.hasData()) { - result.recipe = recipe.jsonData(); - } - - return result; - } - - biomesData() { - return this.biomes.map(biome => { - return {id: biome.id, spawnChance: biome.spawnChance(this)}; - }); - } - - canPickup() { - return this.data.permanent == 0 && this.data.floor == 0; - } - - canMove() { - return this.transitionsAway.find(t => t.move > 0); - } - - hasSprite() { - return this.sprites.length > 0; - } - - sortWeight() { - return -this.id; - } - - // See ObjectInspector.vue for difficulty levels - difficulty() { - if (!this.depth.craftable || !this.depth.difficulty) return; - return Number.parseFloat(this.depth.difficulty).toPrecision(3); - } - - numSlots() { - return this.data.numSlots; - } - - isTool() { - for (var transition of this.transitionsAway) { - if (transition.actor == this && transition.target && transition.tool) return true; - } - return false; - } - - craftable() { - return this.depth.craftable > 0 || this.isNatural(); - } - - isCraftableContainer() { - return this.data.numSlots > 0 && this.data.slotSize >= 1 && !this.isGrave(); - } - - isGrave() { - return this.name.includes("Grave"); - } - - isNatural() { - return this.data.mapChance > 0; - } - - isClothing() { - return this.data.clothing != "n" && (this.data.rValue > 0 || this.data.foodValue == '0' && this.data.containable == '1'); - } - - isWaterSource() { - for (var transition of this.transitionsAway) { - if (transition.actorID == '209' // Empty water pouch - && transition.newActorID == '210' // Full water pouch - && transition.target == this - && (transition.tool || transition.targetRemains)) return true; - } - return false; - } - - isVisible() { - return !this.isCategory(); - } - - isCategory() { - return this.category && !this.category.pattern || this.name && this.name.startsWith("@"); - } - - isDeadly() { - return this.data.deadlyDistance && !this.hasSickTransition(); - } - - isGlobalTrigger() { - return this.name.startsWith(">"); - } - - transmitterName() { - return this.name.replace(">", "*"); - } - - canFilter() { - return this.depth.craftable && !this.isGlobalTrigger(); - } - - sounds() { - if (!this.data.sounds) return []; - const sounds = this.data.sounds.map(sound => sound.split(":")[0]); - return sounds.filter((sound,index) => sound > 0 && sounds.indexOf(sound) === index); - } - - hasSickTransition() { - for (let transition of this.transitionsAway.concat(this.transitionsToward)) { - if (transition.targetID == "0" && transition.newTarget && transition.newTarget.name.includes(" sick")) { - return true; - } - } - return false; - } - - techTreeNodes(depth) { - const transition = this.transitionsToward[0]; - if (this.isNatural() || !transition) - return null; - if (depth == 0) - return []; // Empty array means tree goes deeper - var nodes = []; - if (transition.decay) - nodes.push({decay: transition.decay}); - if (transition.actor) - nodes.push(transition.actor.techTreeNode(depth)); - if (transition.target) - nodes.push(transition.target.techTreeNode(depth)); - return nodes; - } - - techTreeNode(depth) { - return { - id: this.id, - nodes: this.techTreeNodes(depth - 1) - }; - } - - insulation() { - const parts = {'h': 0.25, 't': 0.35, 'b': 0.2, 's': 0.1, 'p': 0.1}; - if (parts[this.data.clothing]) - return parts[this.data.clothing]*this.data.rValue; - } -} - -module.exports = GameObject; diff --git a/process/src/GameObject.ts b/process/src/GameObject.ts new file mode 100644 index 000000000..9973d3038 --- /dev/null +++ b/process/src/GameObject.ts @@ -0,0 +1,616 @@ +"use strict"; + +import { Sprite } from "./Sprite"; +import { Depth } from "./Depth"; +import { ExportedRecipeJson, Recipe } from "./Recipe"; +import { ExportedTransitionData, Transition } from "./Transition"; +import { Category } from "./Category"; +import { Biome, ExportedBiomeObjectData } from "./Biome"; + +interface SlotPosData { + slotPos?: number[]; + vert?: number; + parent?: number; +} + +interface GameObjectData { + backFootIndex?: number[]; + biomes?: number[]; // goes with MapChance + blocksWalking?: number; + bodyIndex?: number[]; + clothing?: string; + clothingOffset?: number[]; + containOffset?: number[]; + containSize?: number; + containable?: number; + creationSoundForce?: number; + creationSoundInitialOnly?: number; + deadlyDistance?: number; + deathMarker?: number; + drawBehindPlayer?: number; + floor?: number; + floorHugging?: number; + foodValue?: number[]; + frontFootIndex?: number[]; + frontWall?: number; + headIndex?: number[]; + heatValue?: number; + heldInHand?: number; + heldOffset?: number[]; + homeMarker?: number; + id?: string; + leftBlockingRadius?: number; + mapChance?: number; + male?: number; + minPickupAge?: number; + name?: string; + noFlip?: number; + noSpawn?: number; + numSlots?: number; + numSprites?: number; + numUses?: number; + partialFloor?: number; + permanent?: number; + person?: number; + pixHeight?: number; + rValue?: number; + ridingAnimationIndex?: number; + rightBlockingRadius?: number; + sideAccess?: number; + slotPosData?: SlotPosData[]; + slotSize?: number; + slotStyle?: number; + slotsLocked?: number; + slotsNoSwap?: number; + sounds?: string[]; + speedMult?: number; + sprites?: Sprite[]; + spritesAdditiveBlend?: number[]; + timeStretch?: number; + useAppearIndex?: number[]; + useChance?: number; + useDistance?: number; + useVanishIndex?: number[]; + vertSlotRot?: number; + wallLayer?: number; +} + +class GameObject { + containable: number; + legacy: boolean; + id: string; + data: GameObjectData; + transitionsToward: Transition[]; + transitionsAway: Transition[]; + categories: Category[]; + biomes: Biome[]; + depth: Depth; + name: string; + version: string; + category: Category; + rotation: number; + index: number; + + constructor(dataText: string) { + this.data = {}; + this.transitionsToward = []; + this.transitionsAway = []; + this.categories = []; + this.biomes = []; + this.depth = new Depth({craftable: false, difficulty: 0}); + this.parseData(dataText); + if (!this.data.id) + return; + this.id = this.data.id.toString(); + this.name = this.data.name; + } + + isSpriteData(data: string): boolean { + if (data.includes("spriteID") + || data.includes("pos") + || data.includes("rot") + || data.includes("hFlip") + || data.includes("color") + || data.includes("ageRange") + || data.includes("parent") + || data.includes("invisHolding") + || data.includes("invisCont") + || data.includes("spritesDrawnBehind") + || data.includes("spritesAdditiveBlend") + || data.includes("ignoredCont") + ) { + return true; + } else { + return false; + } + } + + parseSlotPos(data: string): SlotPosData { + const result: SlotPosData = {}; + + // Split the string into key-value pairs + const pairs = data.split(','); + pairs[1] = pairs[0] + "," + pairs[1]; + pairs.shift(); + + for (const pair of pairs) { + const [key, value] = pair.split('='); + + // Assign the parsed value to the appropriate key in the result object + switch (key) { + case 'slotPos': + result.slotPos = value.split(',').map(v => parseFloat(v)); + break; + case 'vert': + result.vert = parseInt(value); + break; + case 'parent': + result.parent = parseInt(value); + break; + } + } + + return result; + } + + parseData(dataText: string): void { + const lines = dataText.split('\n'); + for (let i = 0; i < lines.length; i++) { + if (i === 1) { + this.parseName(lines[i]); + } else if (lines[i].includes('spriteID')) { + if (!this.data.sprites) { + this.data.sprites = []; + } + // Look forward, gathering all relevant sprite data and incrementing LCV as needed + // Stop when we have lines that don't match sprite data lines, or if we hit a new spriteID. + let spriteData = [lines[i++]]; + while (this.isSpriteData(lines[i]) && !lines[i].includes('spriteID')) { + spriteData.push(lines[i++]); + } + // Back up one line, because of the final increment from the while loop. + i -= 1; + this.parseSprite(spriteData); + } else if (lines[i].includes('slotPos')) { + this.parseSlotPos(lines[i]) + } else { + this.parseLine(lines[i]); + } + } + } + + parseName(name: string): void { + if (name) + this.data.name = name.replace(/#/g, ' - '); + } + + parseLine(line: string): void { + const assignments = line.split(/[,#]/); + let attribute = null; + let values: string[] = []; + for (let assignment of assignments) { + const parts = assignment.split(/[_=]/); + if (parts.length > 1) { + this.assignData(attribute, values); + attribute = parts.shift(); + values = []; + } + values.push(parts[0]); + } + this.assignData(attribute, values); + } + + // parseValue(value) { + // if (isNaN(value)) + // return value; + // if (value.includes(".")) + // return parseFloat(value); + // return parseInt(value); + // } + + assignData(attribute: string, values: string[]): void { + if (!attribute) return; + // Parse attributes. Try to keep this alphabetized, for sanity's sake + if (attribute === "backFootIndex") { + this.data.backFootIndex = values.map(v => parseInt(v)); + } else if (attribute === "biomes") { + this.data.biomes = values.map(v => parseInt(v)); + } else if (attribute === "blocksWalking") { + this.data.blocksWalking = parseInt(values[0]); + } else if (attribute === "bodyIndex") { + this.data.bodyIndex = values.map(v => parseInt(v)); + } else if (attribute === "clothing") { + this.data.clothing = values[0]; + } else if (attribute === "clothingOffset") { + this.data.clothingOffset = [values[0], values[1]].map(v => parseInt(v)); + } else if (attribute === "containOffset") { + this.data.containOffset = [values[0], values[1]].map(v => parseInt(v)); + } else if (attribute === "containSize") { + this.data.containSize = parseFloat(values[0]); + } else if (attribute === "containable") { + this.data.containable = parseInt(values[0]); + } else if (attribute === "creationSoundForce") { + this.data.creationSoundForce = parseInt(values[0]); + } else if (attribute === "creationSoundInitialOnly") { + this.data.creationSoundInitialOnly = parseInt(values[0]); + } else if (attribute === "deadlyDistance") { + this.data.deadlyDistance = parseInt(values[0]); + } else if (attribute === "deathMarker") { + this.data.deathMarker = parseInt(values[0]); + } else if (attribute === "drawBehindPlayer") { + this.data.drawBehindPlayer = parseInt(values[0]); + } else if (attribute === "floor") { + this.data.floor = parseInt(values[0]); + } else if (attribute === "floorHugging") { + this.data.floorHugging = parseInt(values[0]); + } else if (attribute === "foodValue") { + if (values.length == 1) values.push('0'); + this.data.foodValue = [values[0], values[1]].map(v => parseInt(v)); + } else if (attribute === "frontFootIndex") { + this.data.frontFootIndex = values.map(v => parseInt(v)); + } else if (attribute === "frontWall") { + this.data.frontWall = parseInt(values[0]); + } else if (attribute === "headIndex") { + this.data.headIndex = values.map(v => parseInt(v)); + } else if (attribute === "heatValue") { + this.data.heatValue = parseInt(values[0]); + } else if (attribute === "heldInHand") { + this.data.heldInHand = parseInt(values[0]); + } else if (attribute === "heldOffset") { + this.data.heldOffset = [values[0], values[1]].map(v => parseFloat(v)); + } else if (attribute === "homeMarker") { + this.data.homeMarker = parseInt(values[0]); + } else if (attribute === "id") { + this.data.id = values[0]; + } else if (attribute === "leftBlockingRadius") { + this.data.leftBlockingRadius = parseInt(values[0]); + } else if (attribute === "mapChance") { + this.data.mapChance = parseFloat(values[0]); + } else if (attribute === "male") { + this.data.male = parseInt(values[0]); + } else if (attribute === "minPickupAge") { + this.data.minPickupAge = parseInt(values[0]); + } else if (attribute === "name") { + this.data.name = values[0]; + } else if (attribute === "noFlip") { + this.data.noFlip = parseInt(values[0]); + } else if (attribute === "noSpawn") { + this.data.noSpawn = parseInt(values[0]); + } else if (attribute === "numSlots") { + this.data.numSlots = parseInt(values[0]); + } else if (attribute === "numSprites") { + this.data.numSprites = parseInt(values[0]); + } else if (attribute === "numUses") { + this.data.numUses = parseInt(values[0]); + this.data.useChance = parseFloat(values[1] || '1.0'); + } else if (attribute === "partialFloor") { + this.data.partialFloor = parseInt(values[0]); + } else if (attribute === "permanent") { + this.data.permanent = parseInt(values[0]); + } else if (attribute === "person") { + this.data.person = parseInt(values[0]); + } else if (attribute === "pixHeight") { + this.data.pixHeight = parseInt(values[0]); + } else if (attribute === "rValue") { + this.data.rValue = parseFloat(values[0]); + } else if (attribute === "ridingAnimationIndex") { + this.data.ridingAnimationIndex = parseInt(values[0]); + } else if (attribute === "rightBlockingRadius") { + this.data.rightBlockingRadius = parseInt(values[0]); + } else if (attribute === "sideAccess") { + this.data.sideAccess = parseInt(values[0]); + } else if (attribute === "slotSize") { + this.data.slotSize = parseFloat(values[0]); + } else if (attribute === "slotStyle") { + this.data.slotStyle = parseInt(values[0]); + } else if (attribute === "slotsLocked") { + this.data.slotsLocked = parseInt(values[0]); + } else if (attribute === "slotsNoSwap") { + this.data.slotsNoSwap = parseInt(values[0]); + } else if (attribute === "sounds") { + this.data.sounds = values; + } else if (attribute === "speedMult") { + this.data.speedMult = parseFloat(values[0]); + } else if (attribute === "spritesAdditiveBlend") { + this.data.spritesAdditiveBlend = values.map(v => parseInt(v)); + } else if (attribute === "timeStretch") { + this.data.timeStretch = parseInt(values[0]); + } else if (attribute === "useAppearIndex") { + this.data.useAppearIndex = values.map(v => parseInt(v)); + } else if (attribute === "useDistance") { + this.data.useDistance = parseInt(values[0]); + } else if (attribute === "useVanishIndex") { + this.data.useVanishIndex = values.map(v => parseInt(v)); + } else if (attribute === "vertSlotRot") { + this.data.vertSlotRot = parseFloat(values[0]); + } else if (attribute === "wallLayer") { + this.data.wallLayer = parseInt(values[0]); + } else { + console.log(`WARNING: Unhandled data {"${attribute}": ${JSON.stringify(values)}`); + } + } + + parseSprite(lines: string[]): void { + this.data.sprites.push(new Sprite(lines, this.data.sprites.length, this)); + } + + canPickup(): boolean { + return this.data.permanent == 0 && this.data.floor == 0; + } + + canMove(): boolean { + return this.transitionsAway.some(t => t.move > 0); + } + + hasSprite(): boolean { + return this.data.sprites.length > 0; + } + + sortWeight(): number { + return -this.id; + } + + // See ObjectInspector.vue for difficulty levels + difficulty(): string { + if (!this.depth.craftable || !this.depth.difficulty) return; + return this.depth.difficulty.toPrecision(3); + } + + numSlots(): number { + return this.data.numSlots; + } + + isTool(): boolean { + for (var transition of this.transitionsAway) { + if (transition.actor == this && transition.target && transition.tool) return true; + } + return false; + } + + craftable(): boolean { + return this.depth.craftable || this.isNatural(); + } + + isCraftableContainer(): boolean { + return this.data.numSlots > 0 && this.data.slotSize >= 1 && !this.isGrave(); + } + + isGrave(): boolean { + return this.name.includes("Grave"); + } + + isNatural(): boolean { + return this.data.mapChance > 0; + } + + isClothing(): boolean { + return this.data.clothing != "n" && (this.data.rValue > 0 || this.data.foodValue[0] == 0 && this.data.containable == 1); + } + + isWaterSource(): boolean { + for (var transition of this.transitionsAway) { + if (transition.actorID == '209' // Empty water pouch + && transition.newActorID == '210' // Full water pouch + && transition.target == this + && (transition.tool || transition.targetRemains)) return true; + } + return false; + } + + isVisible(): boolean { + return !this.isCategory(); + } + + isCategory(): boolean { + return this.category && !this.category.pattern || this.name && this.name.startsWith("@"); + } + + isDeadly(): boolean { + return this.data.deadlyDistance && !this.hasSickTransition(); + } + + isGlobalTrigger(): boolean { + return this.name.startsWith(">"); + } + + transmitterName() { + return this.name.replace(">", "*"); + } + + canFilter(): boolean { + return this.depth.craftable && !this.isGlobalTrigger(); + } + + sounds(): number[] { + if (!this.data.sounds) return []; + const sounds = this.data.sounds.map(sound => parseInt(sound.split(":")[0])); + return sounds.filter((sound,index) => sound > 0 && sounds.indexOf(sound) === index); + } + + hasSickTransition(): boolean { + for (let transition of this.transitionsAway.concat(this.transitionsToward)) { + if (transition.targetID == "0" && transition.newTarget && transition.newTarget.name.includes(" sick")) { + return true; + } + } + return false; + } + + techTreeNodes(depth: number): TechTreeNode[] { + const transition = this.transitionsToward[0]; + if (this.isNatural() || !transition) + return null; + if (depth == 0) + return []; // Empty array means tree goes deeper + var nodes: TechTreeNode[] = []; + if (transition.decay) + nodes.push({decay: transition.decay}); + if (transition.actor) + nodes.push(transition.actor.techTreeNode(depth)); + if (transition.target) + nodes.push(transition.target.techTreeNode(depth)); + return nodes; + } + + techTreeNode(depth: number): TechTreeNode { + return { + id: this.id, + nodes: this.techTreeNodes(depth - 1), + }; + } + + insulation(): number { + const parts = {'h': 0.25, 't': 0.35, 'b': 0.2, 's': 0.1, 'p': 0.1}; + if (Object.getOwnPropertyNames(parts).includes(this.data.clothing) && parts[this.data.clothing as keyof typeof parts]) + return parts[this.data.clothing as keyof typeof parts]*this.data.rValue; + else + return 0; + } + + jsonData(): ExportedGameObjectData { + const transitionsToward = this.transitionsToward; + const transitionsAway = this.transitionsAway.filter(t => !t.decay); + const transitionsTimed = this.transitionsAway.filter(t => t.decay); + const result: ExportedGameObjectData = { + id: this.id, + name: this.name, + transitionsToward: transitionsToward.map(t => t.jsonData()), + transitionsAway: transitionsAway.map(t => t.jsonData()), + transitionsTimed: transitionsTimed.map(t => t.jsonData()), + }; + + if (this.version) { + result.version = this.version; + } + + if (this.data.foodValue[0] > 0) { + result.foodValue = this.data.foodValue; + } + + if (this.data.heatValue > 0) { + result.heatValue = this.data.heatValue; + } + + if (this.data.numUses > 1) { + result.numUses = this.data.numUses; + if (this.data.useChance != 1) + result.useChance = this.data.useChance; + } + + result.craftable = this.depth.craftable; + if (this.depth.craftable) { + result.depth = this.depth.value; + } + + if (this.data.clothing != "n") { + result.clothing = this.data.clothing; + result.insulation = this.insulation(); + } else if (this.data.rValue > 0 && (this.data.floor == 1 || this.data.blocksWalking == 1)) { + result.insulation = this.data.rValue; + } + + if (this.isDeadly()) { + result.deadlyDistance = this.data.deadlyDistance; + } + + if (this.data.useDistance > 1 && this.data.deadlyDistance > 1) { + result.useDistance = this.data.useDistance; + } + + if (this.data.mapChance > 0) { + result.mapChance = this.data.mapChance; + result.biomes = this.biomesJsonData(); + } + + if (this.data.numSlots > 0) { + result.numSlots = this.data.numSlots; + result.slotSize = this.data.slotSize; + } + + if (this.data.containable == 1) { + result.size = this.data.containSize; + } + + if (this.canPickup()) { + result.minPickupAge = this.data.minPickupAge || 3; + } + + if (this.data.speedMult != 1) { + result.speedMult = this.data.speedMult; + } + + if (this.data.blocksWalking == 1) { + result.blocksWalking = true; + } + + const sounds = this.sounds(); + if (sounds.length > 0) { + result.sounds = sounds; + } + + const moveTransition = this.transitionsAway.find(t => t.move > 0); + if (moveTransition) { + result.moveType = moveTransition.move; + result.moveDistance = moveTransition.desiredMoveDist; + } + + const techTree = this.techTreeNodes(3); + if (techTree) { + result.techTree = techTree; + } + + const recipe = new Recipe(this); + recipe.generate(); + if (recipe.hasData()) { + result.recipe = recipe.jsonData(); + } + + return result; + } + + biomesJsonData(): ExportedBiomeObjectData[] { + return this.biomes.map(biome => { + return {id: biome.id, spawnChance: biome.spawnChance(this)}; + }); + } +} + +interface ExportedGameObjectData { + id?: string, + name?: string, + transitionsToward?: ExportedTransitionData[], + transitionsAway?: ExportedTransitionData[], + transitionsTimed?: ExportedTransitionData[], + version?: string; + foodValue?: number[]; + heatValue?: number; + numUses?: number; + useChance?: number; + craftable?: boolean; + depth?: number; + clothing?: string; + insulation?: number; + deadlyDistance?: number; + useDistance?: number; + mapChance?: number; + biomes?: ExportedBiomeObjectData[]; + numSlots?: number; + slotSize?: number; + size?: number; + minPickupAge?: number; + speedMult?: number; + blocksWalking?: boolean; + sounds?: number[]; + moveType?: number; + moveDistance?: number; + techTree?: TechTreeNode[]; + recipe?: ExportedRecipeJson; +} + +interface TechTreeNode { + id?: string; + nodes?: TechTreeNode[]; + decay?: string; +} + +export { GameObject } diff --git a/process/src/Git.js b/process/src/Git.ts similarity index 79% rename from process/src/Git.js rename to process/src/Git.ts index 551632dc0..1861ce617 100644 --- a/process/src/Git.js +++ b/process/src/Git.ts @@ -1,13 +1,20 @@ "use strict"; -const { spawnSync } = require('child_process'); +import { spawnSync } from 'child_process'; + +interface ChangeLogEntry { + sha: string, + date: Date, + message: string, +} class Git { - constructor(dir) { + dir: string; + constructor(dir: string) { this.dir = dir; } - run(...args) { + run(...args: string[]): string { const result = spawnSync("git", args, {cwd: this.dir, encoding: 'utf8'}); if (result.status > 0) { console.log("Git command failed with args", args); @@ -19,19 +26,19 @@ class Git { return result.stdout; } - runLines(...args) { + runLines(...args: string[]): string[] { return this.run(...args).split("\n").filter(l => l); } - tags() { + tags(): string[] { return this.runLines("tag", "-l"); } - fileChanges(from, to) { + fileChanges(from: string, to: string): string[][] { return this.runLines("diff", "--name-status", `${from}..${to}`).map(line => line.split(/\s+/)); } - fileContent(sha, path) { + fileContent(sha: string, path: string): string { // Dear future reader // Curse object 8316. This is a last ditch effort to fix it. // Broken commit causing errors. An object was removed before all references to it was. @@ -57,7 +64,7 @@ class Git { return this.run("show", `${sha}:${path}`); } - log(from, to) { + log(from: string, to: string): ChangeLogEntry[] { const lines = this.runLines("log", "--format=%H %ad %s", "--date=iso-strict", `${from}..${to}`); return lines.map(line => { const parts = line.match(/^(.+?) (.+?) (.+?)$/).slice(1); @@ -70,4 +77,4 @@ class Git { } } -module.exports = Git; +export { Git, ChangeLogEntry } diff --git a/process/src/MainProcessor.js b/process/src/MainProcessor.js deleted file mode 100644 index f0b996cc2..000000000 --- a/process/src/MainProcessor.js +++ /dev/null @@ -1,94 +0,0 @@ -"use strict"; - -const GameData = require('./GameData'); - -class MainProcessor { - constructor(processDir) { - this.processDir = processDir; - } - - staticDir(edge) { - if (edge && !process.env.ONETECH_MOD_NAME) { - return this.processDir + "/../public/static-edge"; - } - return this.processDir + "/../public/static"; - } - - dataDir() { - return process.env.ONETECH_PROCESS_GIT_PATH || (this.processDir + "/OneLifeData7"); - } - - gitUrl() { - return process.env.ONETECH_PROCESS_GIT_URL || "https://github.com/twohoursonelife/OneLifeData7.git"; - } - - process(version) { - const gameData = new GameData(this.processDir, this.dataDir(), this.staticDir(!version)); - - if (this.doDownload) { - console.log("Downloading data..."); - gameData.download(this.gitUrl()); - } else { - gameData.verifyDownloaded(); - } - - if (version) { - console.log(`Checking out v${version.id}...`); - gameData.checkoutVersion(version); - } else { - gameData.checkoutMaster(); - } - - console.log("Preparing directories..."); - gameData.prepareStaticDir(); - - console.log("Importing objects..."); - gameData.importObjects(); - gameData.importCategories(); - gameData.importTransitions(); - gameData.importBiomes(); - - console.log("Populating versions..."); - gameData.populateVersions(); - - console.log("Calculating object depth..."); - gameData.calculateObjectDepth(); - - if (this.doSprites) { - console.log("Converting sprite images..."); - gameData.convertSpriteImages(); - gameData.convertGroundImages(); - - console.log("Processing sprites..."); - gameData.processSprites(); - } - - if (this.doSounds) { - console.log("Converting sound files..."); - gameData.convertSounds(); - } - - console.log("Exporting objects..."); - gameData.exportObjects(); - - // console.log("Exporting versions..."); - // gameData.exportVersions(); - - console.log("Exporting biomes..."); - gameData.exportBiomes(); - - if (version) { - console.log("Generating sitemap..."); - gameData.generateSitemap(); - return null; - } - - if (process.env.ONETECH_MOD_NAME) { - return null; - } - - return gameData.unprocessedVersion(this.staticDir(false), !this.doDownload); - } -} - -module.exports = MainProcessor; diff --git a/process/src/MainProcessor.ts b/process/src/MainProcessor.ts new file mode 100644 index 000000000..0a1030a62 --- /dev/null +++ b/process/src/MainProcessor.ts @@ -0,0 +1,143 @@ +"use strict"; + +import { ChangeLogVersion } from "./ChangeLogVersion"; +import { GameData } from "./GameData"; + +class MainProcessor { + processDir: string; + doDownload: boolean; + doSprites: boolean; + doSounds: boolean; + constructor(processDir: string) { + this.processDir = processDir; + } + + staticDir(edge: boolean): string { + if (edge && !process.env.ONETECH_MOD_NAME) { + return this.processDir + "/../public/static-edge"; + } + return this.processDir + "/../public/static"; + } + + dataDir(): string { + return process.env.ONETECH_PROCESS_GIT_PATH || (this.processDir + "/OneLifeData7"); + } + + gitUrl(): string { + return process.env.ONETECH_PROCESS_GIT_URL || "https://github.com/twohoursonelife/OneLifeData7.git"; + } + + process(version: ChangeLogVersion): ChangeLogVersion { + // double-equals used to cover undefined case too. + const gameData = new GameData(this.processDir, this.dataDir(), this.staticDir(version == null)); + console.time("Processing took"); + + if (this.doDownload) { + console.log("\nDownloading data..."); + console.time("Downloading data took"); + gameData.download(this.gitUrl()); + console.timeEnd("Downloading data took"); + } else { + gameData.verifyDownloaded(); + } + + if (version) { + console.log(`Checking out v${version.id}...`); + console.time(`Checking out v${version.id} took`); + gameData.checkoutVersion(version); + console.timeEnd(`Checking out v${version.id} took`); + } else { + gameData.checkoutMaster(); + } + + console.log("\nPreparing directories..."); + console.time("Preparing directories took"); + gameData.prepareStaticDir(); + console.timeEnd("Preparing directories took"); + + console.log("\nImporting objects..."); + console.time("Importing objects took"); + gameData.importObjects(); + console.timeEnd("Importing objects took"); + + console.log("\nImporting categories..."); + console.time("Importing categories took"); + gameData.importCategories(); + console.timeEnd("Importing categories took"); + + console.log("\nImporting transitions..."); + console.time("Importing transitions took"); + gameData.importTransitions(); + console.timeEnd("Importing transitions took"); + + console.log("\nImporting biomes..."); + console.time("Importing biomes took"); + gameData.importBiomes(); + console.timeEnd("Importing biomes took"); + + console.log("\nPopulating versions..."); + console.time("Populating versions took"); + gameData.populateVersions(); + console.timeEnd("Populating versions took"); + + console.log("\nCalculating object depth..."); + console.time("Calculating object depth took"); + gameData.calculateObjectDepth(); + console.timeEnd("Calculating object depth took"); + + if (this.doSprites) { + console.log("\nConverting sprite images..."); + console.time("Converting sprite images took"); + gameData.convertSpriteImages(); + console.timeEnd("Converting sprite images took"); + + console.log("\nConverting ground images..."); + console.time("Converting ground images took"); + gameData.convertGroundImages(); + console.timeEnd("Converting ground images took"); + + console.log("\nProcessing sprites..."); + console.time("Processing sprites took"); + gameData.processSprites(); + console.timeEnd("Processing sprites took"); + } + + if (this.doSounds) { + console.log("\nConverting sound files..."); + console.time("Converting sound files took"); + gameData.convertSounds(); + console.timeEnd("Converting sound files took"); + } + + console.log("\nExporting objects..."); + console.time("Exporting objects took"); + gameData.exportObjects(); + console.timeEnd("Exporting objects took"); + + // console.log("\nExporting versions..."); + // gameData.exportVersions(); + + console.log("\nExporting biomes..."); + console.time("Exporting biomes took"); + gameData.exportBiomes(); + console.timeEnd("Exporting biomes took"); + + if (version) { + console.log("\nGenerating sitemap..."); + console.time("Generating sitemap took"); + gameData.generateSitemap(); + console.timeEnd("Generating sitemap took"); + return null; + } + + console.timeEnd("Processing took"); + + if (process.env.ONETECH_MOD_NAME) { + return null; + } + + return gameData.unprocessedVersion(this.staticDir(false), !this.doDownload); + } +} + +export { MainProcessor } diff --git a/process/src/ObjectBadges.js b/process/src/ObjectBadges.js deleted file mode 100644 index d571d2dbe..000000000 --- a/process/src/ObjectBadges.js +++ /dev/null @@ -1,101 +0,0 @@ -"use strict"; - -const Clothing = { - key: "clothing", - filter(objects) { - return objects.filter(o => o.isClothing()); - }, - value(object) { - const percent = (object.insulation()*10000).toFixed()/100 - return `${percent}%`; - } -} - -const Food = { - key: "food", - filter(objects) { - return objects.filter(o => o.data.foodValue[0] > 0); - }, - value(object) { - if (object.data.numUses > 1) - return `${object.data.foodValue[0] + object.data.foodValue[1] + parseInt(process.env.ONETECH_FOOD_BONUS)} x ${object.data.numUses}`; - return object.data.foodValue[0] + object.data.foodValue[1] + parseInt(process.env.ONETECH_FOOD_BONUS); - } -} - -const Tool = { - key: "tool", - filter(objects) { - return objects.filter(o => o.isTool()); - }, - value(object) { - if (object.data.numUses > 1) { - if (object.data.useChance && object.data.useChance != 1) - return `~${(object.data.numUses-1) * (1 / object.data.useChance) + 1}`; - return object.data.numUses; - } - } -} - -const Container = { - key: "container", - filter(objects) { - return objects.filter(o => o.isCraftableContainer()); - }, - value(object) { - return object.data.numSlots; - } -} - -const HeatSource = { - key: "heat", - filter(objects) { - return objects.filter(o => o.data.heatValue > 0); - }, - value(object) { - return object.data.heatValue; - } -} - -const WaterSource = { - key: "water", - filter(objects) { - return objects.filter(o => o.isWaterSource()); - }, - value(object) { - return object.data.numUses > 1 ? object.data.numUses : ""; - } -} - -const Natural = { - key: "natural", - filter(objects) { - return objects.filter(o => o.isNatural()); - } -} - -const ObjectBadges = { - badges: [ - Clothing, - Food, - Tool, - Container, - WaterSource, - HeatSource, - Natural, - ], - jsonData(allObjects) { - allObjects = allObjects.filter(o => o.canFilter()); - const badgesData = {}; - for (let badge of this.badges) { - const objects = badge.filter(allObjects); - const data = {ids: objects.map(o => o.id)}; - if (badge.value) - data.values = objects.map(o => badge.value(o)); - badgesData[badge.key] = data; - } - return badgesData; - } -} - -module.exports = ObjectBadges; diff --git a/process/src/ObjectBadges.ts b/process/src/ObjectBadges.ts new file mode 100644 index 000000000..d50294cee --- /dev/null +++ b/process/src/ObjectBadges.ts @@ -0,0 +1,121 @@ +"use strict"; + +import { GameObject } from "./GameObject"; + +const Clothing: ObjectBadge = { + key: "clothing", + filter(objects) { + return objects.filter(o => o.isClothing()); + }, + value(object: GameObject) { + const percent = Math.round(object.insulation()*10000)/100; + return `${percent}%`; + } +} + +const Food: ObjectBadge = { + key: "food", + filter(objects) { + return objects.filter(o => o.data.foodValue[0] > 0); + }, + value(object) { + if (object.data.numUses > 1) + return `${object.data.foodValue[0] + object.data.foodValue[1] + parseInt(process.env.ONETECH_FOOD_BONUS || '0')} x ${object.data.numUses}`; + return (object.data.foodValue[0] + object.data.foodValue[1] + parseInt(process.env.ONETECH_FOOD_BONUS || '0')).toString(); + } +} + +const Tool: ObjectBadge = { + key: "tool", + filter(objects) { + return objects.filter(o => o.isTool()); + }, + value(object) { + if (object.data.numUses > 1) { + if (object.data.useChance && object.data.useChance != 1) + return `~${(object.data.numUses-1) * (1 / object.data.useChance) + 1}`; + return object.data.numUses.toString(); + } + } +} + +const Container: ObjectBadge = { + key: "container", + filter(objects) { + return objects.filter(o => o.isCraftableContainer()); + }, + value(object) { + return object.data.numSlots.toString(); + } +} + +const HeatSource: ObjectBadge = { + key: "heat", + filter(objects) { + return objects.filter(o => o.data.heatValue > 0); + }, + value(object) { + return object.data.heatValue.toString(); + } +} + +const WaterSource: ObjectBadge = { + key: "water", + filter(objects) { + return objects.filter(o => o.isWaterSource()); + }, + value(object) { + return object.data.numUses > 1 ? object.data.numUses.toString() : ""; + } +} + +const Natural: ObjectBadge = { + key: "natural", + filter(objects) { + return objects.filter(o => o.isNatural()); + } +} + +interface ObjectBadge { + key: string; + filter: (objects: GameObject[]) => GameObject[]; + value?: (object: GameObject) => string; +} + +class ObjectBadges { + badges: ObjectBadge[]; + + constructor() { + this.badges = [ + Clothing, + Food, + Tool, + Container, + WaterSource, + HeatSource, + Natural, + ]; + } + + jsonData(allObjects: GameObject[]): ExportedObjectBadgesData { + allObjects = allObjects.filter(o => o.canFilter()); + const badgesData: ExportedObjectBadgesData = {}; + for (let badge of this.badges) { + const objects = badge.filter(allObjects); + const data: ExportedObjectBadgeData = {ids: objects.map(o => o.id)}; + if (badge.value) + data.values = objects.map(o => badge.value(o)); + badgesData[badge.key] = data; + } + return badgesData; + } +} + +interface ExportedObjectBadgeData { + ids: string[]; + values?: string[]; +} + +type ExportedObjectBadgesData = {[key: string]: ExportedObjectBadgeData}; + +export {ObjectBadges, ExportedObjectBadgesData} \ No newline at end of file diff --git a/process/src/ObjectFilters.js b/process/src/ObjectFilters.ts similarity index 70% rename from process/src/ObjectFilters.js rename to process/src/ObjectFilters.ts index 60e2ad796..5bfa5468a 100644 --- a/process/src/ObjectFilters.js +++ b/process/src/ObjectFilters.ts @@ -1,8 +1,10 @@ "use strict"; +import { GameObject } from "./GameObject"; + // Clothing and its sub-filters -const Clothing_Head = { +const Clothing_Head: ObjectFilter = { key: "head", name: "Head", path: "", @@ -12,7 +14,7 @@ const Clothing_Head = { } } -const Clothing_Top = { +const Clothing_Top: ObjectFilter = { key: "top", name: "Top", path: "", @@ -22,7 +24,7 @@ const Clothing_Top = { } } -const Clothing_Pack = { +const Clothing_Pack: ObjectFilter = { key: "pack", name: "Pack", path: "", @@ -32,7 +34,7 @@ const Clothing_Pack = { } } -const Clothing_Bottom = { +const Clothing_Bottom: ObjectFilter = { key: "bottom", name: "Bottom", path: "", @@ -42,7 +44,7 @@ const Clothing_Bottom = { } } -const Clothing_Shoe = { +const Clothing_Shoe: ObjectFilter = { key: "shoe", name: "Shoe", path: "", @@ -52,7 +54,7 @@ const Clothing_Shoe = { } } -const Clothing = { +const Clothing: ObjectFilter = { key: "clothing", name: "Clothing", path: "", @@ -69,7 +71,7 @@ const Clothing = { } // Food -const Food = { +const Food: ObjectFilter = { key: "food", name: "Food", path: "", @@ -80,7 +82,7 @@ const Food = { } // Tools -const Tools = { +const Tools: ObjectFilter = { key: "tools", name: "Tools", path: "", @@ -91,7 +93,7 @@ const Tools = { } // Containers and its subfilters -const SmallContainers = { +const SmallContainers: ObjectFilter = { key: "small", name: "Small", path: "", @@ -101,7 +103,7 @@ const SmallContainers = { } } -const LargeContainers = { +const LargeContainers: ObjectFilter = { key: "large", name: "Large", path: "", @@ -111,7 +113,7 @@ const LargeContainers = { } } -const ExtraLargeContainers = { +const ExtraLargeContainers: ObjectFilter = { key: "extra_large", name: "Extra Large", path: "", @@ -121,7 +123,7 @@ const ExtraLargeContainers = { } } -const OtherContainers = { +const OtherContainers: ObjectFilter = { key: "other", name: "Other Sizes", path: "", @@ -131,7 +133,7 @@ const OtherContainers = { } } -const Containers = { +const Containers: ObjectFilter = { key: "containers", name: "Containers", path: "", @@ -147,7 +149,7 @@ const Containers = { } // HeatSources -const HeatSources = { +const HeatSources: ObjectFilter = { key: "heat", name: "Heat Sources", path: "", @@ -158,7 +160,7 @@ const HeatSources = { } // WaterSources -const WaterSources = { +const WaterSources: ObjectFilter = { key: "water", name: "Water Sources", path: "", @@ -169,7 +171,7 @@ const WaterSources = { } // Natural -const Natural = { +const Natural: ObjectFilter = { key: "natural", name: "Natural", path: "", @@ -179,7 +181,7 @@ const Natural = { } } -function setup_filters_recursively(filter, gameObjects, path) { +function setup_filters_recursively(filter: ObjectFilter, gameObjects: GameObject[], path: string): ObjectFilter { filter.path = path + `/${filter.key}`; if (filter.filter_single) { filter.ids = gameObjects.filter(o => filter.filter_single(o)).map(o => o.id); @@ -190,25 +192,42 @@ function setup_filters_recursively(filter, gameObjects, path) { return filter; } -const ObjectFilters = { - filters: { - "clothing": Clothing, - "food": Food, - "tools": Tools, - "containers": Containers, - "heat": HeatSources, - "natural": Natural, - }, - jsonData(objects) { +interface ObjectFilter { + key: string, + name: string, + path: string, + subfilters: Record, + filter_single: (object: GameObject) => boolean, + ids?: string[], +} + +class ObjectFilters { + filters: Record; + constructor() { + this.filters = { + "clothing": Clothing, + "food": Food, + "tools": Tools, + "containers": Containers, + "heat": HeatSources, + "natural": Natural, + }; + } + + setupFilters(objects: GameObject[]): void { objects = objects.filter(o => o.canFilter()); - const modifiedFilters = {}; Object.entries(this.filters).forEach(([f_key, f_val]) => { // For each top level filter, we need to go into each of f.subfilters (recursively), and populate their ids with their filters let modifiedFilter = setup_filters_recursively(f_val, objects, "/filter"); - modifiedFilters[f_key] = modifiedFilter; + this.filters[f_key] = modifiedFilter; }); - return modifiedFilters; + } + + jsonData(): ExportedObjectFilterData { + return this.filters; } } -module.exports = ObjectFilters; +type ExportedObjectFilterData = Record; + +export { ObjectFilters, ObjectFilter, ExportedObjectFilterData } diff --git a/process/src/Recipe.js b/process/src/Recipe.ts similarity index 63% rename from process/src/Recipe.js rename to process/src/Recipe.ts index 3a8a82936..6848ea543 100644 --- a/process/src/Recipe.js +++ b/process/src/Recipe.ts @@ -1,14 +1,17 @@ "use strict"; -const RecipeGenerator = require('./RecipeGenerator'); -const RecipeNode = require('./RecipeNode'); +import { GameObject } from "./GameObject"; +import { RecipeGenerator } from "./RecipeGenerator"; +import { ExportedRecipeNodeJson, RecipeNode } from "./RecipeNode"; class Recipe { - constructor(object) { + object: GameObject; + nodes: RecipeNode[]; + constructor(object: GameObject) { this.object = object; } - generate() { + generate(): void { // if (this.object.id == 2620) { // global.debug = true; // } @@ -17,12 +20,12 @@ class Recipe { this.nodes = generator.nodes; } - hasData() { + hasData(): boolean { return this.nodes.length > 1; } - jsonData() { - const data = {steps: RecipeNode.steps(this.nodes)}; + jsonData(): ExportedRecipeJson { + const data: ExportedRecipeJson = {steps: RecipeNode.steps(this.nodes)}; // For now let's just merge tools and ingredients together when displaying // We may eventually split them up for the user @@ -39,12 +42,12 @@ class Recipe { return data; } - tools() { + tools(): GameObject[] { return this.nodes.filter(n => n.tool && !n.parentsAreTools()).map(n => n.object); } - ingredients() { - const ingredients = []; + ingredients(): GameObject[] { + const ingredients: GameObject[] = []; const nodes = this.nodes.filter(n => n.isIngredient()); for (let node of nodes) { const count = node.count(); @@ -56,4 +59,10 @@ class Recipe { } } -module.exports = Recipe; +interface ExportedRecipeJson { + steps?: ExportedRecipeNodeJson[][]; + ingredients?: string[]; + uncraftables?: string[]; +} + +export { Recipe, ExportedRecipeJson } diff --git a/process/src/RecipeGenerator.js b/process/src/RecipeGenerator.ts similarity index 80% rename from process/src/RecipeGenerator.js rename to process/src/RecipeGenerator.ts index 02ff59356..cf56e9f69 100644 --- a/process/src/RecipeGenerator.js +++ b/process/src/RecipeGenerator.ts @@ -1,15 +1,21 @@ "use strict"; -const RecipeNode = require('./RecipeNode'); +import { GameObject } from "./GameObject"; +import { RecipeNode } from "./RecipeNode"; +import { Transition } from "./Transition"; class RecipeGenerator { - constructor(object) { + nodes: RecipeNode[]; + object: GameObject; + availableTools: GameObject[]; + + constructor(object: GameObject) { this.object = object; this.nodes = []; this.availableTools = []; } - generate() { + generate(): void { try { const root = this.generateNode(this.object); root.trackMainBranch(); @@ -20,7 +26,7 @@ class RecipeGenerator { } } - generateNode(object) { + generateNode(object: GameObject): RecipeNode { const node = new RecipeNode(object); if (this.availableTools.includes(object)) { node.makeTool(this); @@ -33,7 +39,7 @@ class RecipeGenerator { return node; } - lookupTransition(node) { + lookupTransition(node: RecipeNode): Transition { let transition = node.object.transitionsToward[0]; if (!transition) return; @@ -54,7 +60,7 @@ class RecipeGenerator { return transition; } - collapseDecayTransition(node, transition, depth) { + collapseDecayTransition(node: RecipeNode, transition: Transition, depth: number): Transition { if (depth > 10) { console.log(`Detected infinite loop collapsing decay transitions for ${this.object.name}`); // debugger; @@ -62,7 +68,7 @@ class RecipeGenerator { } if (transition.totalDecaySeconds() > 0 && transition.target.depth.value) { - node.decaySeconds += parseInt(transition.totalDecaySeconds()); + node.decaySeconds += transition.totalDecaySeconds(); const nextTransition = transition.target.transitionsToward[0]; if (nextTransition.totalDecaySeconds() > 0) { return this.collapseDecayTransition(node, nextTransition, depth+1); @@ -71,7 +77,7 @@ class RecipeGenerator { return transition; } - generateTransitionNodes(node) { + generateTransitionNodes(node: RecipeNode): void { if (!node.transition) return; this.addAvailableTool(node.transition.newActor, node, 0); @@ -81,7 +87,7 @@ class RecipeGenerator { this.generateChildNode(node.transition.target, node); } - generateChildNode(object, parent) { + generateChildNode(object: GameObject, parent: RecipeNode): void { if (!object) return; let node = this.nodes.find(n => n.object == object); if (!node) @@ -89,11 +95,11 @@ class RecipeGenerator { node.addParent(parent); } - deleteNode(node) { + deleteNode(node: RecipeNode): void { this.nodes = this.nodes.filter(n => n != node); } - addAvailableTool(object, parent, recursionCount) { + addAvailableTool(object: GameObject, parent: RecipeNode, recursionCount: number) { if (!object || object == parent.object || this.availableTools.includes(object)) return; if (object.depth.compare(parent.object.depth) < 0) { @@ -115,4 +121,4 @@ class RecipeGenerator { } } -module.exports = RecipeGenerator; +export { RecipeGenerator } diff --git a/process/src/RecipeNode.js b/process/src/RecipeNode.ts similarity index 79% rename from process/src/RecipeNode.js rename to process/src/RecipeNode.ts index 8e2f5e86a..459adc026 100644 --- a/process/src/RecipeNode.js +++ b/process/src/RecipeNode.ts @@ -1,21 +1,24 @@ "use strict"; -class RecipeNode { - static steps(nodes, expand = false) { - const steps = []; - nodes = nodes.sort((a,b) => b.subNodeDepth() - a.subNodeDepth()). - sort((a,b) => (b.collapsedParent ? 0 : 1) - (a.collapsedParent ? 0 : 1)) - for (let node of nodes) { - if (node.showInStep(expand)) { - if (!steps[node.depth()]) - steps[node.depth()] = [] - steps[node.depth()].push(node.jsonData(expand)); - } - } - return steps.filter(s => s).reverse(); - } +import { GameObject } from "./GameObject"; +import { RecipeGenerator } from "./RecipeGenerator"; +import { Transition } from "./Transition"; - constructor(object) { +class RecipeNode { + transition: Transition; + object: GameObject; + parents: RecipeNode[]; + children: RecipeNode[]; + decaySeconds: number; + tool: boolean; + collapsedParent: RecipeNode; + cachedDepth: number; + countCache: number; + cachedSubNodes: RecipeNode[]; + mainBranch: boolean; + cachedLargestChild: RecipeNode; + + constructor(object: GameObject) { this.object = object; this.parents = []; this.children = []; @@ -24,19 +27,19 @@ class RecipeNode { this.collapsedParent = null; } - addParent(parent) { + addParent(parent: RecipeNode) { this.parents.push(parent); parent.children.push(this); } - depth() { + depth(): number { if (!this.cachedDepth) { this.cachedDepth = this.calculateDepth(); } return this.cachedDepth; } - calculateDepth() { + calculateDepth(): number { if (this.parents.length === 0) { return 0; } @@ -49,21 +52,21 @@ class RecipeNode { return depths.sort((a,b) => b - a)[0] + 1; } - collapsedDepth() { + collapsedDepth(): number { if (this.collapsedParent) { return this.collapsedParent.depth(); } return this.depth(); } - makeTool(generator) { + makeTool(generator: RecipeGenerator) { if (this.tool) return; this.tool = true; this.children.forEach(child => child.deleteToolNode(generator)); this.children = []; } - deleteToolNode(generator) { + deleteToolNode(generator: RecipeGenerator) { this.parents = this.parents.filter(p => !p.tool); if (this.parents.length === 0) { this.tool = true; // So children will remove this node @@ -72,30 +75,30 @@ class RecipeNode { } } - showInStep(expand) { + showInStep(expand: boolean): boolean { return !this.isLast() && (!this.isCollapsed() || expand); } - isIngredient() { + isIngredient(): boolean { return !this.tool && this.object.isNatural(); } - isUncraftable() { + isUncraftable(): boolean { return !this.tool && !this.isIngredient() && !this.object.depth.value; } - isLast() { + isLast(): boolean { return this.tool || this.isIngredient() || this.isUncraftable(); } - count() { + count(): number { if (!this.countCache) { this.countCache = this.calculateCount(); } return this.countCache; } - maxUses() { + maxUses(): number { const numUses = this.object.data.numUses; if (numUses && numUses > 1) { for (let parent of this.parents) { @@ -107,7 +110,7 @@ class RecipeNode { return 1; } - maxUsesFor(child) { + maxUsesFor(child: RecipeNode): boolean { if (!this.transition) return false; if (this.transition.actor === child.object) { return this.transition.actorMinUseFraction == 1; @@ -115,13 +118,13 @@ class RecipeNode { return this.transition.targetMinUseFraction == 1; } - calculateCount() { + calculateCount(): number { if (this.tool) return 1; if (this.parents.length == 0) return 1; return Math.ceil(this.uniqueParents().map(n => n.countFor(this)).reduce((t, c) => t + c, 0)); } - countFor(child) { + countFor(child: RecipeNode): number { // if (global.debug && child.object.id == 2448) { // debugger; // } @@ -131,7 +134,7 @@ class RecipeNode { return this.count() * this.requiredUsesFor(child) / this.availableUsesFor(child); } - requiredUsesFor(child) { + requiredUsesFor(child: RecipeNode): number { let uses = 0; if (this.transition.actor == child.object) { uses += this.actorCount(); @@ -142,20 +145,20 @@ class RecipeNode { return uses; } - isReverseUse() { + isReverseUse(): boolean { return this.object.data.numUses && this.object.data.numUses > 1 && (this.transition.newActor == this.object && this.transition.reverseUseActor || this.transition.newTarget == this.object && this.transition.reverseUseTarget); } - actorCount() { + actorCount(): number { if (this.isReverseUse() && this.isObjectUsedToIncrement(this.transition.actor)) { return this.maxUses(); } return 1; } - targetCount() { + targetCount(): number { if (this.transition.target != this.transition.actor) { if (this.isReverseUse() && this.isObjectUsedToIncrement(this.transition.target)) { return this.maxUses(); @@ -164,7 +167,7 @@ class RecipeNode { return 1; } - isObjectUsedToIncrement(object) { + isObjectUsedToIncrement(object: GameObject): boolean { for (let transition of this.object.transitionsAway) { if (transition != this.transition && !transition.lastUseTarget && @@ -183,7 +186,7 @@ class RecipeNode { } } - availableUsesFor(child) { + availableUsesFor(child: RecipeNode): number { let numUses = child.object.data.numUses || 1; if (numUses > 1 && !this.applyUseFor(child)) { numUses = 1; @@ -191,7 +194,7 @@ class RecipeNode { return numUses + this.remainderUses(this.transition); } - applyUseFor(child) { + applyUseFor(child: RecipeNode): boolean { const transition = this.transition; if (transition.actor && transition.applyActorUse() && transition.target && transition.applyTargetUse()) { // This is a special case where both sides look like tools @@ -202,7 +205,7 @@ class RecipeNode { transition.target == child.object && transition.applyTargetUse(); } - remainderUses(transition, depth = 0) { + remainderUses(transition: Transition, depth = 0): number { if (depth > 10) { console.log(`Detected infinite loop calculating remainder for ${this.object.name}`); // debugger; @@ -223,7 +226,7 @@ class RecipeNode { // This is to check for a similar transition which results in the same object // Such as picking a charcoal out of a small charcoal pile - remainderUseTransition(remainder) { + remainderUseTransition(remainder: GameObject): Transition { for (let transition of remainder.transitionsAway) { if (transition.newActor === this.object || transition.newTarget === this.object) { // Make sure we are using the same actor or target so we don't count chisel being put on split rock again @@ -235,7 +238,7 @@ class RecipeNode { } } - remainder(transition) { + remainder(transition: Transition): GameObject { if (!transition) return null; if (transition.newActor === this.object) { return transition.newTarget; @@ -243,18 +246,18 @@ class RecipeNode { return transition.newActor; } - subNodes() { + subNodes(): RecipeNode[] { if (!this.cachedSubNodes) this.cachedSubNodes = this.calculateSubNodes(); return this.cachedSubNodes; } - collapsedSubNodes() { + collapsedSubNodes(): RecipeNode[] { return this.subNodes().filter(n => n.collapsedParent == this); } - calculateSubNodes() { - let subNodes = []; + calculateSubNodes(): RecipeNode[] { + let subNodes: RecipeNode[] = []; for (let child of this.uniqueChildren()) { if (!child.isLast()) { subNodes.push(child); @@ -264,29 +267,29 @@ class RecipeNode { return subNodes.filter((s,i) => subNodes.indexOf(s) == i); } - isExpandable() { + isExpandable(): boolean { return this.collapsedParent == this && this.collapsedSubNodes().length > 0; } - isCollapsed() { + isCollapsed(): boolean { return this.collapsedParent && this.collapsedParent != this; } - subNodeDepth() { + subNodeDepth(): number { if (this.subNodes().length == 0) return 0; return this.subNodes().map(n => n.depth()).sort((a,b) => b - a)[0]; } - uniqueChildren() { + uniqueChildren(): RecipeNode[] { return this.children.filter((c,i) => this.children.indexOf(c) == i); } - uniqueParents() { + uniqueParents(): RecipeNode[] { return this.parents.filter((p,i) => this.parents.indexOf(p) == i); } - trackMainBranch() { + trackMainBranch(): void { this.mainBranch = true; const child = this.uniqueChildren().sort((a,b) => b.subNodes().length - a.subNodes().length)[0]; if (child) { @@ -294,7 +297,7 @@ class RecipeNode { } } - collapseBranches() { + collapseBranches(): void { for (let child of this.children) { if (child.mainBranch) { child.collapseBranches(); @@ -304,14 +307,14 @@ class RecipeNode { } } - largestChild() { + largestChild(): RecipeNode { if (!this.cachedLargestChild) { this.cachedLargestChild = this.children.sort((a,b) => b.subNodes().length - a.subNodes().length)[0]; } return this.cachedLargestChild; } - collapse(parent = null) { + collapse(parent: RecipeNode = null): void { // Don't collapse the main branch if (this.mainBranch) { return; @@ -324,12 +327,12 @@ class RecipeNode { this.children.forEach(c => c.collapse(parent)); } - differentCollapsedParent(parent) { + differentCollapsedParent(parent: RecipeNode): RecipeNode { return this.parents.find(p => p.collapsedParent != parent); } - jsonData(expand = false) { - const data = {id: this.object.id}; + jsonData(expand: boolean = false): ExportedRecipeNodeJson { + const data: ExportedRecipeNodeJson = {id: this.object.id}; if (this.count() > 1) { data.count = this.count(); data.uses = "x" + data.count; @@ -378,13 +381,45 @@ class RecipeNode { return data; } - subSteps() { - return RecipeNode.steps([this].concat(this.collapsedSubNodes()), true); + static steps(nodes: RecipeNode[], expand = false): ExportedRecipeNodeJson[][] { + const steps: ExportedRecipeNodeJson[][] = []; + nodes = nodes.sort((a,b) => b.subNodeDepth() - a.subNodeDepth()). + sort((a,b) => (b.collapsedParent ? 0 : 1) - (a.collapsedParent ? 0 : 1)) + for (let node of nodes) { + if (node.showInStep(expand)) { + if (!steps[node.depth()]) + steps[node.depth()] = [] + steps[node.depth()].push(node.jsonData(expand)); + } + } + return steps.filter(s => s).reverse(); + } + + subSteps(): ExportedRecipeNodeJson[][] { + return RecipeNode.steps([this, ...this.collapsedSubNodes()], true); } - parentsAreTools() { + parentsAreTools(): boolean { return this.parents.filter(p => p.tool).length == this.parents.length; } } -module.exports = RecipeNode; +interface ExportedRecipeNodeJson { + id?: string; + count?: number; + uses?: string; + mainBranch?: boolean; + depth?: number; + subSteps?: ExportedRecipeNodeJson[][]; + actorID?: string; + actorUses?: string; + targetID?: string; + targetUses?: string; + weight?: number; + decay?: string; + hand?: boolean; + targetPlayer?: boolean; + +} + +export { RecipeNode, ExportedRecipeNodeJson } diff --git a/process/src/SitemapGenerator.js b/process/src/SitemapGenerator.ts similarity index 72% rename from process/src/SitemapGenerator.js rename to process/src/SitemapGenerator.ts index 71708bb9b..125d14af6 100644 --- a/process/src/SitemapGenerator.js +++ b/process/src/SitemapGenerator.ts @@ -3,25 +3,28 @@ const sm = require('sitemap'); const fs = require('fs'); -const ObjectFilters = require('./ObjectFilters'); +import { Biome } from "./Biome"; +import { GameObject } from "./GameObject"; +import { ObjectFilter, ObjectFilters } from "./ObjectFilters"; class SitemapGenerator { - constructor(rootDir) { + rootDir: string; + constructor(rootDir: string) { this.rootDir = rootDir; } - generate(objects, biomes) { + generate(objects: GameObject[], filters: Record, biomes: Biome[]): void { const sitemap = sm.createSitemap({hostname: 'https://twotech.twohoursonelife.com'}); sitemap.add({url: "/"}); - function addFilter(filter) { + function addFilter(filter: ObjectFilter) { sitemap.add({url: filter.path}); Object.values(filter.subfilters).forEach((subfilter) => { addFilter(subfilter); }); } - for (let filter of Object.values(ObjectFilters.filters)) { + for (let filter of Object.values(filters)) { addFilter(filter); } @@ -45,4 +48,4 @@ class SitemapGenerator { } } -module.exports = SitemapGenerator; +export { SitemapGenerator } diff --git a/process/src/Sprite.js b/process/src/Sprite.js deleted file mode 100644 index b9d157ae0..000000000 --- a/process/src/Sprite.js +++ /dev/null @@ -1,72 +0,0 @@ -"use strict"; - -const fs = require('fs'); - -class Sprite { - constructor(lines, index, object) { - this.index = index; - this.object = object; - for (let line of lines) { - this.parseLine(line); - } - } - - // Dupication with GameObject.js - parseLine(line) { - const assignments = line.split(/[,#]/); - let attribute = null; - let values = []; - for (let assignment of assignments) { - const parts = assignment.split(/[_=]/); - if (parts.length > 1) { - this.assignData(attribute, values); - attribute = parts.shift(); - values = []; - } - values.push(this.parseValue(parts[0])); - } - this.assignData(attribute, values); - } - - parseValue(value) { - if (isNaN(value)) - return value; - if (value.includes(".")) - return parseFloat(value); - return parseInt(value); - } - - assignData(attribute, values) { - if (!attribute) return; - if (attribute === "spriteID") { - this.id = values[0].toString(); - } else if (attribute === "pos") { - this.x = values[0]; - this.y = values[1]; - } else if (attribute === "rot") { - this.rotation = values[0]; - } else if (values.length == 1) { - this[attribute] = values[0]; - } else { - this[attribute] = values; - } - } - - parseExtraData(data) { - this.tag = data[0]; - this.multiplicativeBlending = data[1] === '1'; - this.centerAnchorXOffset = parseFloat(data[2]); - this.centerAnchorYOffset = parseFloat(data[3]); - } - - beyondAge(age) { - return (this.ageRange[0] > -1 || this.ageRange[1] > -1) && (this.ageRange[0] > age || this.ageRange[1] < age); - } - - additiveBlend() { - const additiveIndexes = this.object.data.spritesAdditiveBlend; - return additiveIndexes && additiveIndexes.indexOf(this.index) > -1; - } -} - -module.exports = Sprite; diff --git a/process/src/Sprite.ts b/process/src/Sprite.ts new file mode 100644 index 000000000..679755fe8 --- /dev/null +++ b/process/src/Sprite.ts @@ -0,0 +1,117 @@ +"use strict"; + +import { GameObject } from "./GameObject"; + +const fs = require('fs'); + +class Sprite { + index: number; + object: GameObject; + id: string; + x: number; + y: number; + rotation: number; + tag: string; + multiplicativeBlending: boolean; + centerAnchorXOffset: number; + centerAnchorYOffset: number; + ageRange: number[]; + color: number[]; + width: number; + height: number; + hFlip: number; + invisHolding: number; + invisWorn: number; + behindSlots: number; + parent: number; + invisCont: number; + spritesDrawnBehind: number[]; + spritesAdditiveBlend: number[]; + ignoredCont: number[]; + + constructor(lines: string[], index: number, object: GameObject) { + this.index = index; + this.object = object; + for (let line of lines) { + this.parseLine(line); + } + } + + // Dupication with GameObject.js + parseLine(line: string): void { + const assignments = line.split(/[,#]/); + let attribute = null; + let values: string[] = []; + for (let assignment of assignments) { + const parts = assignment.split(/[_=]/); + if (parts.length > 1) { + this.assignData(attribute, values); + attribute = parts.shift(); + values = []; + } + values.push(parts[0]); + } + this.assignData(attribute, values); + } + + assignData(attribute: string, values: string[]) { + if (!attribute) return; + // Strings first + if (attribute === "spriteID") { + this.id = values[0].toString(); + } + // Floats next + else if (attribute === "rot") { + this.rotation = parseFloat(values[0]); + } else if (attribute === "pos") { + this.x = parseFloat(values[0]); + this.y = parseFloat(values[1]); + } else if (attribute === "ageRange") { + this.ageRange = [values[0], values[1]].map((v) => parseFloat(v)); + } else if (attribute === "color") { + this.color = [values[0], values[1], values[2]].map((v) => parseFloat(v)); + } + // Ints + else if (attribute === "index") { + this.index = parseInt(values[0]); + } else if (attribute === "hFlip") { + this.hFlip = parseInt(values[0]); + } else if (attribute === "invisHolding") { + this.invisHolding = parseInt(values[0]); + } else if (attribute === "invisWorn") { + this.invisWorn = parseInt(values[0]); + } else if (attribute === "behindSlots") { + this.behindSlots = parseInt(values[0]); + } else if (attribute === "parent") { + this.parent = parseInt(values[0]); + } else if (attribute === "invisCont") { + this.invisCont = parseInt(values[0]); + } else if (attribute === "spritesDrawnBehind") { + this.spritesDrawnBehind = values.map(v => parseInt(v)); + } else if (attribute === "spritesAdditiveBlend") { + this.spritesAdditiveBlend = values.map(v => parseInt(v)); + } else if (attribute === "ignoredCont") { + this.ignoredCont = values.map(v => parseInt(v)); + } else { + console.log(`WARNING: Unhandled data {"${attribute}": ${JSON.stringify(values)}`); + } + } + + parseExtraData(data: string[]) { + this.tag = data[0]; + this.multiplicativeBlending = data[1] === '1'; + this.centerAnchorXOffset = parseFloat(data[2]); + this.centerAnchorYOffset = parseFloat(data[3]); + } + + beyondAge(age: number): boolean { + return (this.ageRange[0] > -1 || this.ageRange[1] > -1) && (this.ageRange[0] > age || this.ageRange[1] < age); + } + + additiveBlend(): boolean { + const additiveIndexes = this.object.data.spritesAdditiveBlend; + return additiveIndexes && additiveIndexes.indexOf(this.index) > -1; + } +} + +export { Sprite } diff --git a/process/src/SpriteProcessor.js b/process/src/SpriteProcessor.ts similarity index 66% rename from process/src/SpriteProcessor.js rename to process/src/SpriteProcessor.ts index ca81698a5..6dfc5ff0c 100644 --- a/process/src/SpriteProcessor.js +++ b/process/src/SpriteProcessor.ts @@ -1,23 +1,42 @@ "use strict"; -const Canvas = require('canvas'); +import * as Canvas from 'canvas'; +import { GameObject } from './GameObject'; +import { Sprite } from './Sprite'; const fs = require('fs'); +interface SpriteBounds { + minX: number, + maxX: number, + minY: number, + maxY: number, +} + +interface SpritePoint { + x: number, + y: number, +} + class SpriteProcessor { - constructor(spritesDir, pngDir) { + spritesDir: string; + pngDir: string; + canvas: Canvas.Canvas; + context: Canvas.CanvasRenderingContext2D; + + constructor(spritesDir: string, pngDir: string) { this.spritesDir = spritesDir; this.pngDir = pngDir; - this.canvas = new Canvas.createCanvas(512, 1024); + this.canvas = Canvas.createCanvas(512, 1024); this.context = this.canvas.getContext('2d'); } - process(objects) { - for (var id in objects) { + process(objects: Record): void { + for (let id in objects) { this.processObject(objects[id]); } } - processObject(object) { + processObject(object: GameObject): void { this.renderSprites(this.visibleSprites(object), object.id); // Draw only the last sprite @@ -26,12 +45,12 @@ class SpriteProcessor { } } - visibleSprites(object) { + visibleSprites(object: GameObject): Sprite[] { // Draw sprites as if they were 20 years old - let sprites = object.sprites.filter(sprite => !sprite.beyondAge(20)); + let sprites = object.data.sprites.filter(sprite => !sprite.beyondAge(20)); // Remove multiple use sprites - if (object.data.useVanishIndex == -1 && object.data.numUses > 1) { + if (object.data.useVanishIndex.includes(-1) && object.data.numUses > 1) { sprites = sprites.filter((_s,i) => !object.data.useAppearIndex.includes(i)); } @@ -43,26 +62,26 @@ class SpriteProcessor { return sprites; } - lastSprites(object) { - if (object.data.useVanishIndex != -1 && Array.isArray(object.data.useVanishIndex)) { + lastSprites(object: GameObject): Sprite[] { + if (!object.data.useVanishIndex.includes(-1) && Array.isArray(object.data.useVanishIndex)) { const hideIndexes = object.data.useVanishIndex.slice(0); hideIndexes.shift(); // still draw the first sprite return this.visibleSprites(object).filter((s,i) => !hideIndexes.includes(i)); } - if (object.data.useAppearIndex != -1 && Array.isArray(object.data.useAppearIndex)) { + if (!object.data.useAppearIndex.includes(-1) && Array.isArray(object.data.useAppearIndex)) { const indexes = object.data.useAppearIndex.filter((_, i) => i+1 < object.data.numUses); - const useSprites = object.sprites.filter((s,i) => indexes.includes(i)); + const useSprites = object.data.sprites.filter((s,i) => indexes.includes(i)); const sprites = this.visibleSprites(object); // Insert the use sprites after the last index // add 2 to work around goose pond rendering sprites.splice(indexes.pop() - useSprites.length + 2, 0, ...useSprites); return sprites; } - return object.sprites; + return object.data.sprites; } - renderSprites(sprites, name) { - this.context.setTransform(1, 0, 0, 1, 0, 0); + renderSprites(sprites: Sprite[], name: string): void { + this.context.setTransform(new Canvas.DOMMatrix([1, 0, 0, 1, 0, 0])); this.context.clearRect(0, 0, this.canvas.width, this.canvas.height); for (var sprite of sprites) { @@ -74,10 +93,10 @@ class SpriteProcessor { const width = bounds.maxX - bounds.minX; const height = bounds.maxY - bounds.minY; - const newCanvas = new Canvas.createCanvas(width, height); + const newCanvas = Canvas.createCanvas(width, height); const newContext = newCanvas.getContext('2d'); - newContext.setTransform(1, 0, 0, 1, 0, 0); + newContext.setTransform(new Canvas.DOMMatrix([1, 0, 0, 1, 0, 0])); newContext.drawImage( this.canvas, @@ -94,13 +113,13 @@ class SpriteProcessor { fs.writeFileSync(`${this.pngDir}/obj_${name}.png`, newCanvas.toBuffer()); } - parseSpriteFile(sprite) { + parseSpriteFile(sprite: Sprite): void { const path = `${this.spritesDir}/${sprite.id}.txt` const data = fs.readFileSync(path, "utf8").split(' '); sprite.parseExtraData(data); } - drawSprite(sprite) { + drawSprite(sprite: Sprite): void { if (sprite.additiveBlend()) { this.drawSpriteWithOperation(sprite, "screen"); } else { @@ -108,15 +127,15 @@ class SpriteProcessor { } } - drawSpriteWithOperation(sprite, operation) { - const newCanvas = new Canvas.createCanvas(this.canvas.width, this.canvas.height); + drawSpriteWithOperation(sprite: Sprite, operation: Canvas.GlobalCompositeOperation): void { + const newCanvas = Canvas.createCanvas(this.canvas.width, this.canvas.height); const newContext = newCanvas.getContext('2d'); this.drawSpriteDirectly(sprite, newContext); this.overlayCanvas(newCanvas, this.context, operation); } - drawSpriteDirectly(sprite, context) { + drawSpriteDirectly(sprite: Sprite, context: Canvas.CanvasRenderingContext2D): void { this.drawSpriteImage(sprite, context); if (sprite.color.find(c => c < 1.0) !== undefined) { @@ -124,17 +143,17 @@ class SpriteProcessor { } } - drawSpriteImage(sprite, context) { - var img = new Canvas.Image; + drawSpriteImage(sprite: Sprite, context: Canvas.CanvasRenderingContext2D): void { + const img = new Canvas.Image; img.src = fs.readFileSync(`${this.pngDir}/sprite_${sprite.id}.png`); sprite.width = img.width; sprite.height = img.height; - const angleRads = parseFloat(sprite.rotation) * Math.PI * 2; - const x = parseFloat(sprite.x); - const y = parseFloat(sprite.y); + const angleRads = sprite.rotation * Math.PI * 2; + const x = sprite.x; + const y = sprite.y; - context.setTransform(1, 0, 0, 1, 0, 0); + context.setTransform(new Canvas.DOMMatrix([1, 0, 0, 1, 0, 0])); context.translate(x + context.canvas.width / 2, -y + context.canvas.height / 2); context.rotate(angleRads); if (sprite.hFlip == 1) context.scale(-1, 1); @@ -148,27 +167,27 @@ class SpriteProcessor { ); } - overlayColor(sprite, targetContext) { - const newCanvas = new Canvas.createCanvas(this.canvas.width, this.canvas.height); + overlayColor(sprite: Sprite, targetContext: Canvas.CanvasRenderingContext2D): void { + const newCanvas = Canvas.createCanvas(this.canvas.width, this.canvas.height); const newContext = newCanvas.getContext('2d'); - this.drawSpriteImage(sprite, newContext, false) + this.drawSpriteImage(sprite, newContext) const color = sprite.color.map(c => Math.round(c*255)).join(", "); newContext.globalCompositeOperation = "source-in"; - newContext.setTransform(1, 0, 0, 1, 0, 0); + newContext.setTransform(new Canvas.DOMMatrix([1, 0, 0, 1, 0, 0])); newContext.fillStyle = "rgb(" + color + ")"; newContext.fillRect(0, 0, newCanvas.width, newCanvas.height); this.overlayCanvas(newCanvas, targetContext, "multiply") } - overlayCanvas(sourceCanvas, targetContext, operation) { + overlayCanvas(sourceCanvas: Canvas.Canvas, targetContext: Canvas.CanvasRenderingContext2D, operation: Canvas.GlobalCompositeOperation): void { const previousOperation = targetContext.globalCompositeOperation; targetContext.globalCompositeOperation = operation; - targetContext.setTransform(1, 0, 0, 1, 0, 0); + targetContext.setTransform(new Canvas.DOMMatrix([1, 0, 0, 1, 0, 0])); targetContext.drawImage( sourceCanvas, 0, @@ -180,14 +199,14 @@ class SpriteProcessor { targetContext.globalCompositeOperation = previousOperation; } - spritesBounds(sprites) { - var maxX = 0; - var maxY = 0; - var minX = 0; - var minY = 0; + spritesBounds(sprites: Sprite[]): SpriteBounds { + let maxX = 0; + let maxY = 0; + let minX = 0; + let minY = 0; - for (var sprite of sprites) { - for (var point of this.spritePoints(sprite)) { + for (const sprite of sprites) { + for (const point of this.spritePoints(sprite)) { if (point.x > maxX) maxX = point.x + 2; if (point.x < minX) minX = point.x - 2; if (point.y > maxY) maxY = point.y + 2; @@ -212,7 +231,7 @@ class SpriteProcessor { return {minX, minY, maxX, maxY}; } - leftTrim(image, threshold) { + leftTrim(image: Canvas.ImageData, threshold: number): number { for (let col=0; col < image.width; col++) { let opacity = 0; for (let row=0; row < image.height; row++) { @@ -224,7 +243,7 @@ class SpriteProcessor { // throw "Unable to find opaque pixels in image"; } - rightTrim(image, threshold) { + rightTrim(image: Canvas.ImageData, threshold: number): number { for (let col=image.width-1; col >= 0; col--) { let opacity = 0; for (let row=image.height-1; row >= 0; row--) { @@ -236,7 +255,7 @@ class SpriteProcessor { // throw "Unable to find opaque pixels in image"; } - topTrim(image, threshold) { + topTrim(image: Canvas.ImageData, threshold: number): number { for (let row=0; row < image.height; row++) { let opacity = 0; for (let col=0; col < image.width; col++) { @@ -248,7 +267,7 @@ class SpriteProcessor { // throw "Unable to find opaque pixels in image"; } - bottomTrim(image, threshold) { + bottomTrim(image: Canvas.ImageData, threshold: number): number { for (let row=image.height-1; row >= 0; row--) { let opacity = 0; for (let col=image.width-1; col >= 0; col--) { @@ -260,26 +279,26 @@ class SpriteProcessor { // throw "Unable to find opaque pixels in image"; } - spritePoints(sprite) { + spritePoints(sprite: Sprite): SpritePoint[] { if (!sprite.width || !sprite.height) { return []; } - const x = parseFloat(sprite.x); - const y = parseFloat(sprite.y); + const x = sprite.x; + const y = sprite.y; - var points = [ + const points: SpritePoint[] = [ {x: -sprite.width/2, y: -sprite.height/2}, {x: sprite.width/2, y: -sprite.height/2}, {x: sprite.width/2, y: sprite.height/2}, {x: -sprite.width/2, y: sprite.height/2}, ] - const angleRads = parseFloat(sprite.rotation) * Math.PI * 2; + const angleRads = sprite.rotation * Math.PI * 2; const cosA = Math.cos(angleRads); const sinA = Math.sin(angleRads); - for (var point of points) { + for (const point of points) { point.x -= sprite.centerAnchorXOffset; point.y += sprite.centerAnchorYOffset; point.x = point.x * cosA - point.y * sinA; @@ -291,4 +310,4 @@ class SpriteProcessor { } } -module.exports = SpriteProcessor; +export { SpriteProcessor } diff --git a/process/src/Transition.js b/process/src/Transition.ts similarity index 63% rename from process/src/Transition.js rename to process/src/Transition.ts index cc606884a..421ba1e61 100644 --- a/process/src/Transition.js +++ b/process/src/Transition.ts @@ -1,15 +1,44 @@ "use strict"; -const Depth = require('./Depth'); +import { Depth } from "./Depth"; +import { GameObject } from "./GameObject"; class Transition { - constructor(dataText, filename) { - this.depth = new Depth({}); + depth: Depth; + lastUseActor: boolean; + lastUseTarget: boolean; + actorID: string; + targetID: string; + newActorID: string; + newTargetID: string; + autoDecaySeconds: number; + actorMinUseFraction: number; + targetMinUseFraction: number; + reverseUseActor: boolean; + reverseUseTarget: boolean; + move: number; + desiredMoveDist: number; + noUseActor: boolean; + noUseTarget: boolean; + playerActor: boolean; + tool: boolean; + targetRemains: boolean; + decay: string; + actor: GameObject; + target: GameObject; + newActor: GameObject; + newTarget: GameObject; + newExtraTarget: GameObject; + newExtraTargetID: string; + newActorWeight: number; + newTargetWeight: number; + constructor(dataText: string, filename: string) { + this.depth = new Depth({craftable: false, difficulty: 0}); this.parseFilename(filename); this.parseData(dataText); } - parseFilename(filename) { + parseFilename(filename: string): void { const parts = filename.split('.')[0].split('_'); this.lastUseActor = (parts[2] === 'LA'); this.lastUseTarget = (parts[2] === 'LT' || parts[2] === 'L'); @@ -17,29 +46,29 @@ class Transition { this.targetID = parts[1]; } - parseData(dataText) { + parseData(dataText: string): void { const data = dataText.split(' '); - this.newActorID = data[0] || 0; - this.newTargetID = data[1] || 0; - this.autoDecaySeconds = data[2] || 0; - this.actorMinUseFraction = data[3] || 0; - this.targetMinUseFraction = data[4] || 0; - this.reverseUseActor = data[5] == '1'; - this.reverseUseTarget = data[6] == '1'; - this.move = parseInt(data[7] || 0); - this.desiredMoveDist = data[8] || 1; - this.noUseActor = data[9] == '1'; - this.noUseTarget = data[10] == '1'; - - this.playerActor = this.actorID == 0; - this.tool = this.actorID >= 0 && this.actorID == this.newActorID; - this.targetRemains = this.targetID >= 0 && this.targetID == this.newTargetID; + this.newActorID = data[0] || '0'; + this.newTargetID = data[1] || '0'; + this.autoDecaySeconds = parseInt(data[2]) || 0; + this.actorMinUseFraction = parseInt(data[3]) || 0; + this.targetMinUseFraction = parseInt(data[4]) || 0; + this.reverseUseActor = data[5] === '1'; + this.reverseUseTarget = data[6] === '1'; + this.move = parseInt(data[7] || '0'); + this.desiredMoveDist = parseInt(data[8]) || 1; + this.noUseActor = data[9] === '1'; + this.noUseTarget = data[10] === '1'; + + this.playerActor = this.actorID === '0'; + this.tool = parseInt(this.actorID) >= 0 && this.actorID === this.newActorID; + this.targetRemains = parseInt(this.targetID) >= 0 && this.targetID === this.newTargetID; this.decay = this.calculateDecay(this.autoDecaySeconds); } - calculateDecay(seconds) { + calculateDecay(seconds: number): string { if (seconds < 0) return -seconds + "h"; if (seconds > 0 && seconds % 60 == 0) @@ -48,7 +77,7 @@ class Transition { return seconds + "s"; } - addToObjects(objects) { + addToObjects(objects: Record): void { this.actor = objects[this.actorID]; this.target = objects[this.targetID]; this.newActor = objects[this.newActorID]; @@ -71,63 +100,63 @@ class Transition { this.newExtraTarget.transitionsToward.push(this); } - isGeneric() { + isGeneric(): boolean { return this.targetID === '-1' && this.newTargetID === '0' && this.actorID != this.newActorID; } - matchesGenericTransition(transition) { + matchesGenericTransition(transition: Transition): boolean { if (this == transition) return false; return this.matchesGenericActor(transition) || this.matchesGenericTarget(transition); } - matchesGenericActor(transition) { - return this.actorID == transition.actorID && this.tool && this.targetID > 0; + matchesGenericActor(transition: Transition): boolean { + return this.actorID == transition.actorID && this.tool && parseInt(this.targetID) > 0; } - matchesGenericTarget(transition) { + matchesGenericTarget(transition: Transition): boolean { if (transition.lastUseActor && !this.lastUseTarget) return false; - return this.targetID == transition.actorID && this.targetRemains && this.actorID > 0; + return this.targetID == transition.actorID && this.targetRemains && parseInt(this.actorID) > 0; } - isLastUse() { + isLastUse(): boolean { return this.lastUseActor || this.lastUseTarget; } - targetsPlayer() { - return this.targetID === '0' || this.targetID === '-1' && this.actor.data.foodValue > 0; + targetsPlayer(): boolean { + return this.targetID === '0' || this.targetID === '-1' && (this.actor.data.foodValue[0] + this.actor.data.foodValue[1]) > 0; } - totalDecaySeconds() { + totalDecaySeconds(): number { if (this.autoDecaySeconds > 0 && this.target.data.numUses > 1 && this.lastUseTarget) - return parseInt(this.autoDecaySeconds) * this.target.data.numUses; + return this.autoDecaySeconds * this.target.data.numUses; return this.autoDecaySeconds; } - clone() { + clone(): Transition { return Object.assign(Object.create(Object.getPrototypeOf(this)), this); } - applyActorUse() { + applyActorUse(): boolean { return !this.noUseActor && ( this.tool || this.newActor && this.newActor.data.numUses === this.actor.data.numUses); } - applyTargetUse() { + applyTargetUse(): boolean { return !this.noUseTarget && ( this.targetRemains || this.newTarget && this.newTarget.data.numUses === this.target.data.numUses); } - hand() { + hand(): boolean { return !this.decay && (this.playerActor || !(this.actor && (this.actor.canMove() || this.actor.isGlobalTrigger()))); } - totalDepth() { + totalDepth(): number { let total = 0; if (this.actor) { total += this.actor.depth.value; @@ -138,8 +167,8 @@ class Transition { return total; } - jsonData() { - const result = {} + jsonData(): ExportedTransitionData { + const result: ExportedTransitionData = {} if (this.actor) { result.actorID = this.actor.id; @@ -217,4 +246,24 @@ class Transition { } } -module.exports = Transition; +interface ExportedTransitionData { + actorID?: string; + actorUses?: string; + newActorWeight?: number; + newActorUses?: string; + targetID?: string; + targetUses?: string; + newTargetWeight?: number; + newTargetUses?: string; + newActorID?: string; + newTargetID?: string; + newExtraTargetID?: string; + targetPlayer?: boolean; + targetRemains?: boolean; + hand?: boolean; + tool?: boolean; + decay?: string; + move?: number; +} + +export { Transition, ExportedTransitionData } diff --git a/process/src/TransitionImporter.js b/process/src/TransitionImporter.ts similarity index 68% rename from process/src/TransitionImporter.js rename to process/src/TransitionImporter.ts index 43108f49a..fe7679f6c 100644 --- a/process/src/TransitionImporter.js +++ b/process/src/TransitionImporter.ts @@ -1,22 +1,30 @@ "use strict"; -const Transition = require('./Transition'); +import { Category } from "./Category"; +import { GameObject } from "./GameObject"; +import { Transition } from "./Transition"; + +enum CategorySplitType { + Actor, + Target, +} class TransitionImporter { + transitions: Transition[]; constructor() { this.transitions = []; } - importFromFile(content, filename) { + importFromFile(content: string, filename: string): void { const transition = new Transition(content, filename); this.transitions.push(transition); } - splitCategories(categories) { + splitCategories(categories: Category[]): void { const nonPatternCategories = categories.filter(c => !c.pattern); for (let category of nonPatternCategories) { - this.splitCategory(category, "actorID", "newActorID", "newActorWeight"); - this.splitCategory(category, "targetID", "newTargetID", "newTargetWeight"); + this.splitCategory(category, CategorySplitType.Actor); + this.splitCategory(category, CategorySplitType.Target); } const patternCategories = categories.filter(c => c.pattern); for (let transition of this.transitions) { @@ -25,20 +33,44 @@ class TransitionImporter { this.cleanUpPatternCategories(patternCategories); } - splitCategory(category, attr, newAttr, weightAttr) { - const newTransitions = []; + splitCategory(category: Category, type: CategorySplitType): void { + const newTransitions: Transition[] = []; for (let transition of this.transitions) { - if (transition[attr] == category.parentID || transition[newAttr] == category.parentID) { + let currentId, newId, newWeight; + if (type === CategorySplitType.Actor) { + currentId = transition.actorID; + newId = transition.newActorID; + newWeight = transition.newActorWeight; + } else if (type === CategorySplitType.Target) { + currentId = transition.targetID; + newId = transition.newTargetID; + newWeight = transition.newTargetWeight; + } + + if (currentId == category.parentID || newId == category.parentID) { for (let id of category.objectIDs) { const newTransition = transition.clone(); - if (transition[attr] == category.parentID) - newTransition[attr] = id; - if (transition[newAttr] == category.parentID) - newTransition[newAttr] = id; - if (transition[newAttr] == category.parentID) - newTransition[newAttr] = id; + if (currentId == category.parentID) + { + if (type === CategorySplitType.Actor) { + newTransition.actorID = id; + } else if (type === CategorySplitType.Target) { + newTransition.targetID = id; + } + } + if (newId == category.parentID) { + if (type === CategorySplitType.Actor) { + newTransition.newActorID = id; + } else if (type === CategorySplitType.Target) { + newTransition.newTargetID = id; + } + } if (category.probSet) { - newTransition[weightAttr] = category.objectWeight(id); + if (type === CategorySplitType.Actor) { + newTransition.newActorWeight = category.objectWeight(id); + } else if (type === CategorySplitType.Target) { + newTransition.newTargetWeight = category.objectWeight(id); + } } if (!this.findDuplicate(newTransition)) { newTransitions.push(newTransition); @@ -57,10 +89,14 @@ class TransitionImporter { // categories have the same number of objectIDs // 3. For each objectID, a new transition is created which maps // each other pattern category objectID to the new object - splitPatternCategories(transition, patternCategories) { + splitPatternCategories(transition: Transition, patternCategories: Category[]): void { // if (transition.actorID == 2900 && transition.targetID == 733) // debugger; - const attrs = ["actorID", "targetID", "newActorID", "newTargetID"]; + type StringKeys = { + [K in keyof T]: T[K] extends string ? K : never; + }[keyof T]; + + const attrs: StringKeys[] = ["actorID", "targetID", "newActorID", "newTargetID"]; let categories = attrs.map(attr => { return patternCategories.find(c => c.parentID == transition[attr]); }); @@ -70,7 +106,7 @@ class TransitionImporter { const count = categories.find(c => c).objectIDs.length; categories = categories.map(c => c && c.objectIDs.length == count && c); for (let i=0; i < count; i++) { - const newTransition = transition.clone(); + const newTransition: Transition = transition.clone(); for (let j=0; j < attrs.length; j++) { if (categories[j]) { newTransition[attrs[j]] = categories[j].objectIDs[i]; @@ -83,7 +119,7 @@ class TransitionImporter { } // Remove transitions where pattern category parent is an actual category object - cleanUpPatternCategories(patternCategories) { + cleanUpPatternCategories(patternCategories: Category[]): void { const categories = patternCategories.filter(c => c.parent && c.parent.isCategory()); for (let category of categories) { this.transitions = this.transitions.filter(transition => { @@ -95,7 +131,7 @@ class TransitionImporter { } } - findDuplicate(newTransition) { + findDuplicate(newTransition: Transition): Transition { return this.transitions.find(transition => { if (newTransition.newActorWeight || newTransition.newTargetWeight) { return transition.actorID == newTransition.actorID && @@ -111,8 +147,8 @@ class TransitionImporter { } // Generic transitions are played along with another successful transition of the same actor - mergeGenericTransitions() { - const newTransitions = []; + mergeGenericTransitions(): void { + const newTransitions: Transition[] = []; for (let transition of this.transitions) { if (transition.isGeneric()) { this.mergeGenericTransition(transition, newTransitions); @@ -123,7 +159,7 @@ class TransitionImporter { this.transitions = newTransitions; } - mergeGenericTransition(transition, newTransitions) { + mergeGenericTransition(transition: Transition, newTransitions: Transition[]): void { const otherTransitions = this.transitions.filter(t => t.matchesGenericTransition(transition)); if (otherTransitions.length == 0) { @@ -158,8 +194,8 @@ class TransitionImporter { } } - mergeAttackTransitions() { - const newTransitions = []; + mergeAttackTransitions(): void { + const newTransitions: Transition[] = []; for (let transition of this.transitions) { if (transition.targetID === "0") { if (!transition.lastUseActor && !transition.lastUseTarget) { @@ -173,7 +209,7 @@ class TransitionImporter { this.transitions = newTransitions; } - mergeAttackTransition(transition) { + mergeAttackTransition(transition: Transition): void { const lastUseActorTransition = this.transitions.find(t => t != transition && t.actorID == transition.actorID && t.lastUseActor); const lastUseTargetTransition = this.transitions.find(t => t != transition && t.actorID == transition.actorID && t.lastUseTarget); @@ -191,15 +227,15 @@ class TransitionImporter { transition.newExtraTargetID = (lastUseTargetTransition || transition).newTargetID; transition.newActorID = (lastUseActorTransition || lastUseTargetTransition).newActorID; transition.newTargetID = (lastUseActorTransition || lastUseTargetTransition).newTargetID; - transition.tool = transition.actorID >= 0 && transition.actorID == transition.newActorID; - transition.targetRemains = transition.targetID >= 0 && transition.targetID == transition.newTargetID; + transition.tool = parseInt(transition.actorID) >= 0 && transition.actorID === transition.newActorID; + transition.targetRemains = parseInt(transition.targetID) >= 0 && transition.targetID === transition.newTargetID; } - newDecayTransition(targetID, newTargetID, decaySeconds) { + newDecayTransition(targetID: string, newTargetID: string, decaySeconds: number): Transition { return new Transition(`0 ${newTargetID} ${decaySeconds}`, `-1_${targetID}.txt`); } - addToObjects(objects) { + addToObjects(objects: Record): void { for (let transition of this.transitions) { transition.addToObjects(objects); } @@ -210,11 +246,11 @@ class TransitionImporter { // They have an "away" transition for the receiver, but no // "towards" transition. This looks for a transmitter which // has "*global1" in the name and adds this as an extra object - addGlobalTriggers(objects) { - const triggers = Object.values(objects).filter(o => o.isGlobalTrigger()); + addGlobalTriggers(objects: Record): void { + const triggers: GameObject[] = Object.values(objects).filter((o) => o.isGlobalTrigger()); for (let trigger of triggers) { const transmitterName = trigger.transmitterName(); - const transmitters = Object.values(objects).filter(o => o.name.includes(transmitterName)); + const transmitters: GameObject[] = Object.values(objects).filter((o) => o.name.includes(transmitterName)); for (let transmitter of transmitters) { for (let transition of transmitter.transitionsToward) { transition.newExtraTargetID = trigger.id; @@ -225,4 +261,4 @@ class TransitionImporter { } } -module.exports = TransitionImporter; +export { TransitionImporter } diff --git a/process/src/readFileNormalized.js b/process/src/readFileNormalized.js deleted file mode 100644 index 27d2ccb68..000000000 --- a/process/src/readFileNormalized.js +++ /dev/null @@ -1,9 +0,0 @@ -"use strict"; -const fs = require("fs"); - -/** read file and normalize line endings of CR to LF */ -function readFileNormalized(path) { - return fs.readFileSync(path, "utf8").replaceAll('\r\n', '\n'); -} - -module.exports = readFileNormalized; diff --git a/process/src/readFileNormalized.ts b/process/src/readFileNormalized.ts new file mode 100644 index 000000000..1c6695d54 --- /dev/null +++ b/process/src/readFileNormalized.ts @@ -0,0 +1,9 @@ +"use strict"; +import * as fs from 'fs'; + +/** read file and normalize line endings of CR to LF */ +function readFileNormalized(path: string): string { + return fs.readFileSync(path, "utf8").replace('\r\n', '\n'); +} + +export { readFileNormalized } diff --git a/process/tsconfig.json b/process/tsconfig.json new file mode 100644 index 000000000..e7bdd95f8 --- /dev/null +++ b/process/tsconfig.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "outDir": "./built", + "allowJs": true, + "target": "es5", + "noImplicitAny": true, + }, + "include": [ + "./src/**/*" + ] +} \ No newline at end of file From b33582dff74ac53e2837f2247839742764ac56e4 Mon Sep 17 00:00:00 2001 From: Matt Klass Date: Sat, 31 Aug 2024 13:40:51 +0000 Subject: [PATCH 2/2] Migrate from Vue 2 to Vue 3, and a few processing Typescript fixes --- package-lock.json | 811 ++++++++++++----------- package.json | 16 +- process/package.json | 3 +- process/process.ts | 16 + process/src/GameData.ts | 53 ++ process/src/GameObject.ts | 1 - process/src/MainProcessor.ts | 24 +- process/src/Sprite.ts | 3 - src/App.vue | 178 +++-- src/components/BiomeImage.vue | 28 +- src/components/BiomeInspector.vue | 119 ++-- src/components/BiomeList.vue | 43 +- src/components/ChangeLog.vue | 92 +-- src/components/ChangeLogCommit.vue | 180 ++--- src/components/ChangeLogObjectChange.vue | 62 +- src/components/ChangeLogVersion.vue | 69 +- src/components/NotFound.vue | 21 +- src/components/ObjectBrowser.vue | 152 ++--- src/components/ObjectFilter.vue | 30 +- src/components/ObjectImage.vue | 84 ++- src/components/ObjectImageWrapper.vue | 44 +- src/components/ObjectInspector.vue | 388 ++++++----- src/components/ObjectSearch.vue | 147 ++-- src/components/ObjectView.vue | 83 ++- src/components/Recipe.vue | 109 +-- src/components/RecipeForLetters.vue | 295 +++++---- src/components/RecipeIngredients.vue | 59 +- src/components/RecipeStep.vue | 140 ++-- src/components/RecipeTransition.vue | 58 +- src/components/Select.vue | 206 ++++-- src/components/TechTree.vue | 55 +- src/components/TechTreeNode.vue | 51 +- src/components/TechTreeView.vue | 41 +- src/components/TransitionView.vue | 91 ++- src/components/TransitionsList.vue | 47 +- src/css/tippy.css | 21 +- src/eventBus.js | 2 +- src/main.js | 73 +- src/mixins/pointerScroll.js | 81 --- src/mixins/typeAheadPointer.js | 60 -- src/models/Biome.js | 24 +- src/models/GameObject.js | 50 +- webpack.config.js | 15 +- 43 files changed, 2289 insertions(+), 1836 deletions(-) delete mode 100644 src/mixins/pointerScroll.js delete mode 100644 src/mixins/typeAheadPointer.js diff --git a/package-lock.json b/package-lock.json index c9d6de896..728f9d705 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,16 +9,18 @@ "version": "1.0.0", "license": "MIT", "dependencies": { + "@vueuse/head": "^2.0.0", "lodash": "^4.17.21", "pug": "^3.0.2", - "vue": "^2.7.16", - "vue-meta": "^2.4.0", - "vue-router": "^3.6.5", - "vue-tippy": "^2.1.3" + "style-loader": "^4.0.0", + "vue": "^3.4.38", + "vue-router": "^4.4.3", + "vue-tippy": "^6.4.4" }, "devDependencies": { "@babel/core": "^7.24.4", "@babel/preset-env": "^7.24.4", + "@vue/compiler-sfc": "^3.4.38", "ajv": "^8.12.0", "babel-loader": "^9.1.3", "cross-env": "^7.0.3", @@ -26,8 +28,7 @@ "file-loader": "^6.2.0", "sass": "^1.75.0", "sass-loader": "^14.2.1", - "vue-loader": "^15.11.1", - "vue-template-compiler": "^2.7.16", + "vue-loader": "^17.4.2", "webpack": "^5.91.0", "webpack-cli": "^5.1.4", "webpack-dev-server": "^5.0.4" @@ -378,17 +379,19 @@ } }, "node_modules/@babel/helper-string-parser": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz", - "integrity": "sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==", + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz", + "integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", + "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", + "license": "MIT", "engines": { "node": ">=6.9.0" } @@ -446,9 +449,13 @@ } }, "node_modules/@babel/parser": { - "version": "7.24.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.4.tgz", - "integrity": "sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg==", + "version": "7.25.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.3.tgz", + "integrity": "sha512-iLTJKDbJ4hMvFPgQwwsVoxtHyWpKKPBrxkANrSYewDPaPpT5py5yeVkgPIJ7XYXhndxJpaA3PyALSXQ7u8e/Dw==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.25.2" + }, "bin": { "parser": "bin/babel-parser.js" }, @@ -1701,12 +1708,13 @@ } }, "node_modules/@babel/types": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz", - "integrity": "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==", + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.2.tgz", + "integrity": "sha512-YTnYtra7W9e6/oAZEHj0bJehPRUlLH9/fbpT5LfB0NhQXyALCRkRs3zH9v07IYhkgpqX6Z78FnuccZr/l4Fs4Q==", + "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.23.4", - "@babel/helper-validator-identifier": "^7.22.20", + "@babel/helper-string-parser": "^7.24.8", + "@babel/helper-validator-identifier": "^7.24.7", "to-fast-properties": "^2.0.0" }, "engines": { @@ -1743,7 +1751,6 @@ "version": "0.3.5", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", - "dev": true, "dependencies": { "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", @@ -1757,7 +1764,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, "engines": { "node": ">=6.0.0" } @@ -1766,7 +1772,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "dev": true, "engines": { "node": ">=6.0.0" } @@ -1775,23 +1780,21 @@ "version": "0.3.6", "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", - "dev": true, "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25" } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "dev": true + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.25", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "dev": true, "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" @@ -1813,6 +1816,16 @@ "node": ">=14" } }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, "node_modules/@types/body-parser": { "version": "1.19.5", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", @@ -1855,7 +1868,6 @@ "version": "8.56.10", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.10.tgz", "integrity": "sha512-Shavhk87gCtY2fhXDctcfS3e6FdxWkCx1iUZ9eEUbh7rTqlZT0/IzOkCOVt0fCjcFuZ9FPYfuezTBImfHCDBGQ==", - "dev": true, "dependencies": { "@types/estree": "*", "@types/json-schema": "*" @@ -1865,7 +1877,6 @@ "version": "3.7.7", "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", - "dev": true, "dependencies": { "@types/eslint": "*", "@types/estree": "*" @@ -1874,8 +1885,7 @@ "node_modules/@types/estree": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", - "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", - "dev": true + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==" }, "node_modules/@types/express": { "version": "4.17.21", @@ -1919,8 +1929,7 @@ "node_modules/@types/json-schema": { "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==" }, "node_modules/@types/mime": { "version": "1.3.5", @@ -1932,7 +1941,6 @@ "version": "20.12.7", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.7.tgz", "integrity": "sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==", - "dev": true, "dependencies": { "undici-types": "~5.26.4" } @@ -2012,82 +2020,200 @@ "@types/node": "*" } }, - "node_modules/@vue/compiler-sfc": { - "version": "2.7.16", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-2.7.16.tgz", - "integrity": "sha512-KWhJ9k5nXuNtygPU7+t1rX6baZeqOYLEforUPjgNDBnLicfHCoi48H87Q8XyLZOrNNsmhuwKqtpDQWjEFe6Ekg==", + "node_modules/@unhead/dom": { + "version": "1.9.16", + "resolved": "https://registry.npmjs.org/@unhead/dom/-/dom-1.9.16.tgz", + "integrity": "sha512-aZIAnnc89Csi1vV4mtlHYI765B7m1yuaXUuQiYHwr6glE9FLyy2X87CzEci4yPH/YbkKm0bGQRfcxXq6Eq0W7g==", + "license": "MIT", "dependencies": { - "@babel/parser": "^7.23.5", - "postcss": "^8.4.14", - "source-map": "^0.6.1" + "@unhead/schema": "1.9.16", + "@unhead/shared": "1.9.16" }, - "optionalDependencies": { - "prettier": "^1.18.2 || ^2.0.0" + "funding": { + "url": "https://github.com/sponsors/harlan-zw" } }, - "node_modules/@vue/component-compiler-utils": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/@vue/component-compiler-utils/-/component-compiler-utils-3.3.0.tgz", - "integrity": "sha512-97sfH2mYNU+2PzGrmK2haqffDpVASuib9/w2/noxiFi31Z54hW+q3izKQXXQZSNhtiUpAI36uSuYepeBe4wpHQ==", - "dev": true, + "node_modules/@unhead/schema": { + "version": "1.9.16", + "resolved": "https://registry.npmjs.org/@unhead/schema/-/schema-1.9.16.tgz", + "integrity": "sha512-V2BshX+I6D2wN4ys5so8RQDUgsggsxW9FVBiuQi4h8oPWtHclogxzDiHa5BH2TgvNIoUxLnLYNAShMGipmVuUw==", + "license": "MIT", "dependencies": { - "consolidate": "^0.15.1", - "hash-sum": "^1.0.2", - "lru-cache": "^4.1.2", - "merge-source-map": "^1.1.0", - "postcss": "^7.0.36", - "postcss-selector-parser": "^6.0.2", - "source-map": "~0.6.1", - "vue-template-es2015-compiler": "^1.9.0" + "hookable": "^5.5.3", + "zhead": "^2.2.4" }, - "optionalDependencies": { - "prettier": "^1.18.2 || ^2.0.0" + "funding": { + "url": "https://github.com/sponsors/harlan-zw" } }, - "node_modules/@vue/component-compiler-utils/node_modules/lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", - "dev": true, + "node_modules/@unhead/shared": { + "version": "1.9.16", + "resolved": "https://registry.npmjs.org/@unhead/shared/-/shared-1.9.16.tgz", + "integrity": "sha512-pfJnArULCY+GBr7OtYyyxihRiQLkT31TpyK6nUKIwyax4oNOGyhNfk0RFzNq16BwLg60d1lrc5bd5mZGbfClMA==", + "license": "MIT", "dependencies": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" + "@unhead/schema": "1.9.16" + }, + "funding": { + "url": "https://github.com/sponsors/harlan-zw" } }, - "node_modules/@vue/component-compiler-utils/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", - "dev": true - }, - "node_modules/@vue/component-compiler-utils/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dev": true, + "node_modules/@unhead/ssr": { + "version": "1.9.16", + "resolved": "https://registry.npmjs.org/@unhead/ssr/-/ssr-1.9.16.tgz", + "integrity": "sha512-8R1qt4VAemX4Iun/l7DnUBJqmxA/KaUSc2+/hRYPJYOopXdCWkoaxC1K1ROX2vbRF7qmjdU5ik/a27kSPN94gg==", + "license": "MIT", "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" + "@unhead/schema": "1.9.16", + "@unhead/shared": "1.9.16" }, - "engines": { - "node": ">=6.0.0" + "funding": { + "url": "https://github.com/sponsors/harlan-zw" + } + }, + "node_modules/@unhead/vue": { + "version": "1.9.16", + "resolved": "https://registry.npmjs.org/@unhead/vue/-/vue-1.9.16.tgz", + "integrity": "sha512-kpMWWwm8cOwo4gw4An43pz30l2CqNtmJpX5Xsu79rwf6Viq8jHAjk6BGqyKy220M2bpa0Va4fnR532SgGO1YgQ==", + "license": "MIT", + "dependencies": { + "@unhead/schema": "1.9.16", + "@unhead/shared": "1.9.16", + "hookable": "^5.5.3", + "unhead": "1.9.16" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" + "url": "https://github.com/sponsors/harlan-zw" + }, + "peerDependencies": { + "vue": ">=2.7 || >=3" } }, - "node_modules/@vue/component-compiler-utils/node_modules/yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==", - "dev": true + "node_modules/@vue/compiler-core": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.4.38.tgz", + "integrity": "sha512-8IQOTCWnLFqfHzOGm9+P8OPSEDukgg3Huc92qSG49if/xI2SAwLHQO2qaPQbjCWPBcQoO1WYfXfTACUrWV3c5A==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.24.7", + "@vue/shared": "3.4.38", + "entities": "^4.5.0", + "estree-walker": "^2.0.2", + "source-map-js": "^1.2.0" + } + }, + "node_modules/@vue/compiler-dom": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.4.38.tgz", + "integrity": "sha512-Osc/c7ABsHXTsETLgykcOwIxFktHfGSUDkb05V61rocEfsFDcjDLH/IHJSNJP+/Sv9KeN2Lx1V6McZzlSb9EhQ==", + "license": "MIT", + "dependencies": { + "@vue/compiler-core": "3.4.38", + "@vue/shared": "3.4.38" + } + }, + "node_modules/@vue/compiler-sfc": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.4.38.tgz", + "integrity": "sha512-s5QfZ+9PzPh3T5H4hsQDJtI8x7zdJaew/dCGgqZ2630XdzaZ3AD8xGZfBqpT8oaD/p2eedd+pL8tD5vvt5ZYJQ==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.24.7", + "@vue/compiler-core": "3.4.38", + "@vue/compiler-dom": "3.4.38", + "@vue/compiler-ssr": "3.4.38", + "@vue/shared": "3.4.38", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.10", + "postcss": "^8.4.40", + "source-map-js": "^1.2.0" + } + }, + "node_modules/@vue/compiler-ssr": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.4.38.tgz", + "integrity": "sha512-YXznKFQ8dxYpAz9zLuVvfcXhc31FSPFDcqr0kyujbOwNhlmaNvL2QfIy+RZeJgSn5Fk54CWoEUeW+NVBAogGaw==", + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.4.38", + "@vue/shared": "3.4.38" + } + }, + "node_modules/@vue/devtools-api": { + "version": "6.6.3", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.3.tgz", + "integrity": "sha512-0MiMsFma/HqA6g3KLKn+AGpL1kgKhFWszC9U29NfpWK5LE7bjeXxySWJrOJ77hBz+TBrBQ7o4QJqbPbqbs8rJw==", + "license": "MIT" + }, + "node_modules/@vue/reactivity": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.4.38.tgz", + "integrity": "sha512-4vl4wMMVniLsSYYeldAKzbk72+D3hUnkw9z8lDeJacTxAkXeDAP1uE9xr2+aKIN0ipOL8EG2GPouVTH6yF7Gnw==", + "license": "MIT", + "dependencies": { + "@vue/shared": "3.4.38" + } + }, + "node_modules/@vue/runtime-core": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.4.38.tgz", + "integrity": "sha512-21z3wA99EABtuf+O3IhdxP0iHgkBs1vuoCAsCKLVJPEjpVqvblwBnTj42vzHRlWDCyxu9ptDm7sI2ZMcWrQqlA==", + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.4.38", + "@vue/shared": "3.4.38" + } + }, + "node_modules/@vue/runtime-dom": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.4.38.tgz", + "integrity": "sha512-afZzmUreU7vKwKsV17H1NDThEEmdYI+GCAK/KY1U957Ig2NATPVjCROv61R19fjZNzMmiU03n79OMnXyJVN0UA==", + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.4.38", + "@vue/runtime-core": "3.4.38", + "@vue/shared": "3.4.38", + "csstype": "^3.1.3" + } + }, + "node_modules/@vue/server-renderer": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.4.38.tgz", + "integrity": "sha512-NggOTr82FbPEkkUvBm4fTGcwUY8UuTsnWC/L2YZBmvaQ4C4Jl/Ao4HHTB+l7WnFCt5M/dN3l0XLuyjzswGYVCA==", + "license": "MIT", + "dependencies": { + "@vue/compiler-ssr": "3.4.38", + "@vue/shared": "3.4.38" + }, + "peerDependencies": { + "vue": "3.4.38" + } + }, + "node_modules/@vue/shared": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.38.tgz", + "integrity": "sha512-q0xCiLkuWWQLzVrecPb0RMsNWyxICOjPrcrwxTUEHb1fsnvni4dcuyG7RT/Ie7VPTvnjzIaWzRMUBsrqNj/hhw==", + "license": "MIT" + }, + "node_modules/@vueuse/head": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@vueuse/head/-/head-2.0.0.tgz", + "integrity": "sha512-ykdOxTGs95xjD4WXE4na/umxZea2Itl0GWBILas+O4oqS7eXIods38INvk3XkJKjqMdWPcpCyLX/DioLQxU1KA==", + "license": "MIT", + "dependencies": { + "@unhead/dom": "^1.7.0", + "@unhead/schema": "^1.7.0", + "@unhead/ssr": "^1.7.0", + "@unhead/vue": "^1.7.0" + }, + "peerDependencies": { + "vue": ">=2.7 || >=3" + } }, "node_modules/@webassemblyjs/ast": { "version": "1.12.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==", - "dev": true, "dependencies": { "@webassemblyjs/helper-numbers": "1.11.6", "@webassemblyjs/helper-wasm-bytecode": "1.11.6" @@ -2096,26 +2222,22 @@ "node_modules/@webassemblyjs/floating-point-hex-parser": { "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", - "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", - "dev": true + "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==" }, "node_modules/@webassemblyjs/helper-api-error": { "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", - "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", - "dev": true + "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==" }, "node_modules/@webassemblyjs/helper-buffer": { "version": "1.12.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz", - "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==", - "dev": true + "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==" }, "node_modules/@webassemblyjs/helper-numbers": { "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", - "dev": true, "dependencies": { "@webassemblyjs/floating-point-hex-parser": "1.11.6", "@webassemblyjs/helper-api-error": "1.11.6", @@ -2125,14 +2247,12 @@ "node_modules/@webassemblyjs/helper-wasm-bytecode": { "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", - "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", - "dev": true + "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==" }, "node_modules/@webassemblyjs/helper-wasm-section": { "version": "1.12.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz", "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==", - "dev": true, "dependencies": { "@webassemblyjs/ast": "1.12.1", "@webassemblyjs/helper-buffer": "1.12.1", @@ -2144,7 +2264,6 @@ "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", - "dev": true, "dependencies": { "@xtuc/ieee754": "^1.2.0" } @@ -2153,7 +2272,6 @@ "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", - "dev": true, "dependencies": { "@xtuc/long": "4.2.2" } @@ -2161,14 +2279,12 @@ "node_modules/@webassemblyjs/utf8": { "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", - "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", - "dev": true + "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==" }, "node_modules/@webassemblyjs/wasm-edit": { "version": "1.12.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz", "integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==", - "dev": true, "dependencies": { "@webassemblyjs/ast": "1.12.1", "@webassemblyjs/helper-buffer": "1.12.1", @@ -2184,7 +2300,6 @@ "version": "1.12.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz", "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==", - "dev": true, "dependencies": { "@webassemblyjs/ast": "1.12.1", "@webassemblyjs/helper-wasm-bytecode": "1.11.6", @@ -2197,7 +2312,6 @@ "version": "1.12.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz", "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==", - "dev": true, "dependencies": { "@webassemblyjs/ast": "1.12.1", "@webassemblyjs/helper-buffer": "1.12.1", @@ -2209,7 +2323,6 @@ "version": "1.12.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz", "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==", - "dev": true, "dependencies": { "@webassemblyjs/ast": "1.12.1", "@webassemblyjs/helper-api-error": "1.11.6", @@ -2223,7 +2336,6 @@ "version": "1.12.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz", "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==", - "dev": true, "dependencies": { "@webassemblyjs/ast": "1.12.1", "@xtuc/long": "4.2.2" @@ -2276,14 +2388,12 @@ "node_modules/@xtuc/ieee754": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", - "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "dev": true + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==" }, "node_modules/@xtuc/long": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", - "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", - "dev": true + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==" }, "node_modules/accepts": { "version": "1.3.8", @@ -2519,12 +2629,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", - "dev": true - }, "node_modules/body-parser": { "version": "1.20.2", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", @@ -2608,7 +2712,6 @@ "version": "4.23.0", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", - "dev": true, "funding": [ { "type": "opencollective", @@ -2639,8 +2742,7 @@ "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" }, "node_modules/bundle-name": { "version": "4.1.0", @@ -2688,7 +2790,6 @@ "version": "1.0.30001612", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001612.tgz", "integrity": "sha512-lFgnZ07UhaCcsSZgWW0K5j4e69dK1u/ltrL9lTUiFOwNHs12S3UMIEYgBV0Z6C6hRDev7iRnMzzYmKabYdXF9g==", - "dev": true, "funding": [ { "type": "opencollective", @@ -2754,7 +2855,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", - "dev": true, "engines": { "node": ">=6.0" } @@ -2797,8 +2897,7 @@ "node_modules/commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" }, "node_modules/common-path-prefix": { "version": "3.0.0", @@ -2866,19 +2965,6 @@ "node": ">=0.8" } }, - "node_modules/consolidate": { - "version": "0.15.1", - "resolved": "https://registry.npmjs.org/consolidate/-/consolidate-0.15.1.tgz", - "integrity": "sha512-DW46nrsMJgy9kqAbPt5rKaCr7uFtpo4mSUvLHIUbJEjm0vo+aY5QLwBUq3FK4tRnJr/X0Psc0C4jf/h+HtXSMw==", - "deprecated": "Please upgrade to consolidate v1.0.0+ as it has been modernized with several long-awaited fixes implemented. Maintenance is supported by Forward Email at https://forwardemail.net ; follow/watch https://github.com/ladjs/consolidate for updates and release changelog", - "dev": true, - "dependencies": { - "bluebird": "^3.1.1" - }, - "engines": { - "node": ">= 0.10.0" - } - }, "node_modules/constantinople": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/constantinople/-/constantinople-4.0.1.tgz", @@ -2986,6 +3072,7 @@ "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-5.2.7.tgz", "integrity": "sha512-Q7mOvpBNBG7YrVGMxRxcBJZFL75o+cH2abNASdibkj/fffYD8qWbInZrD0S9ccI6vZclF3DsHE7njGlLtaHbhg==", "dev": true, + "license": "MIT", "dependencies": { "icss-utils": "^5.1.0", "loader-utils": "^2.0.0", @@ -3106,13 +3193,8 @@ "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" - }, - "node_modules/de-indent": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz", - "integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==", - "dev": true + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "license": "MIT" }, "node_modules/debug": { "version": "4.3.4", @@ -3131,14 +3213,6 @@ } } }, - "node_modules/deepmerge": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", - "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/default-browser": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.2.1.tgz", @@ -3264,8 +3338,7 @@ "node_modules/electron-to-chromium": { "version": "1.4.750", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.750.tgz", - "integrity": "sha512-9ItEpeu15hW5m8jKdriL+BQrgwDTXEL9pn4SkillWFu73ZNNNQ2BKKLS+ZHv2vC9UkNhosAeyfxOf/5OSeTCPA==", - "dev": true + "integrity": "sha512-9ItEpeu15hW5m8jKdriL+BQrgwDTXEL9pn4SkillWFu73ZNNNQ2BKKLS+ZHv2vC9UkNhosAeyfxOf/5OSeTCPA==" }, "node_modules/emoji-regex": { "version": "9.2.2", @@ -3295,7 +3368,6 @@ "version": "5.16.0", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.16.0.tgz", "integrity": "sha512-O+QWCviPNSSLAD9Ucn8Awv+poAkqn3T1XY5/N7kR7rQO9yfSGWkYZDwpJ+iKF7B8rxaQKWngSqACpgzeapSyoA==", - "dev": true, "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" @@ -3304,6 +3376,18 @@ "node": ">=10.13.0" } }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/envinfo": { "version": "7.12.0", "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.12.0.tgz", @@ -3338,14 +3422,12 @@ "node_modules/es-module-lexer": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.0.tgz", - "integrity": "sha512-pqrTKmwEIgafsYZAGw9kszYzmagcE/n4dbgwGWLEXg7J4QFJVQRBld8j3Q3GNez79jzxZshq0bcT962QHOghjw==", - "dev": true + "integrity": "sha512-pqrTKmwEIgafsYZAGw9kszYzmagcE/n4dbgwGWLEXg7J4QFJVQRBld8j3Q3GNez79jzxZshq0bcT962QHOghjw==" }, "node_modules/escalade": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", - "dev": true, "engines": { "node": ">=6" } @@ -3369,7 +3451,6 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^4.1.1" @@ -3382,7 +3463,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, "dependencies": { "estraverse": "^5.2.0" }, @@ -3394,7 +3474,6 @@ "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, "engines": { "node": ">=4.0" } @@ -3403,11 +3482,16 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, "engines": { "node": ">=4.0" } }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "license": "MIT" + }, "node_modules/esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", @@ -3436,7 +3520,6 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "dev": true, "engines": { "node": ">=0.8.x" } @@ -3524,14 +3607,12 @@ "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" }, "node_modules/fastest-levenshtein": { "version": "1.0.16", @@ -3873,8 +3954,7 @@ "node_modules/glob-to-regexp": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", - "dev": true + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==" }, "node_modules/globals": { "version": "11.12.0", @@ -3899,8 +3979,7 @@ "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" }, "node_modules/handle-thing": { "version": "2.0.1", @@ -3965,10 +4044,11 @@ } }, "node_modules/hash-sum": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-1.0.2.tgz", - "integrity": "sha512-fUs4B4L+mlt8/XAtSOGMUO1TXmAelItBPtJG7CyHJfYTdDjwisntGO2JQz7oUsatOY9o68+57eziUVNw/mRHmA==", - "dev": true + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-2.0.0.tgz", + "integrity": "sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg==", + "dev": true, + "license": "MIT" }, "node_modules/hasown": { "version": "2.0.2", @@ -3981,14 +4061,11 @@ "node": ">= 0.4" } }, - "node_modules/he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true, - "bin": { - "he": "bin/he" - } + "node_modules/hookable": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/hookable/-/hookable-5.5.3.tgz", + "integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==", + "license": "MIT" }, "node_modules/hpack.js": { "version": "2.1.6", @@ -4499,7 +4576,6 @@ "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", - "dev": true, "dependencies": { "@types/node": "*", "merge-stream": "^2.0.0", @@ -4513,7 +4589,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, "engines": { "node": ">=8" } @@ -4522,7 +4597,6 @@ "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -4559,8 +4633,7 @@ "node_modules/json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" }, "node_modules/json-schema-traverse": { "version": "1.0.0", @@ -4612,7 +4685,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", - "dev": true, "engines": { "node": ">=6.11.5" } @@ -4666,6 +4738,15 @@ "yallist": "^3.0.2" } }, + "node_modules/magic-string": { + "version": "0.30.11", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.11.tgz", + "integrity": "sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0" + } + }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -4697,20 +4778,10 @@ "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", "dev": true }, - "node_modules/merge-source-map": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.1.0.tgz", - "integrity": "sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==", - "dev": true, - "dependencies": { - "source-map": "^0.6.1" - } - }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" }, "node_modules/methods": { "version": "1.1.2", @@ -4750,7 +4821,6 @@ "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, "engines": { "node": ">= 0.6" } @@ -4759,7 +4829,6 @@ "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, "dependencies": { "mime-db": "1.52.0" }, @@ -4797,15 +4866,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/minipass": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", @@ -4863,8 +4923,7 @@ "node_modules/neo-async": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" }, "node_modules/node-forge": { "version": "1.3.1", @@ -4878,8 +4937,7 @@ "node_modules/node-releases": { "version": "2.0.14", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", - "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", - "dev": true + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==" }, "node_modules/normalize-path": { "version": "3.0.0", @@ -5099,9 +5157,10 @@ "dev": true }, "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", + "license": "ISC" }, "node_modules/picomatch": { "version": "2.3.1", @@ -5130,20 +5189,10 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/popper.js": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1.tgz", - "integrity": "sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ==", - "deprecated": "You can find the new Popper v2 at @popperjs/core, this package is dedicated to the legacy v1", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/popperjs" - } - }, "node_modules/postcss": { - "version": "8.4.38", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", - "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", + "version": "8.4.41", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.41.tgz", + "integrity": "sha512-TesUflQ0WKZqAvg52PWL6kHgLKP6xB6heTOdoYM0Wt2UHyxNa4K25EZZMgKns3BH1RLVbZCREPpLY0rhnNoHVQ==", "funding": [ { "type": "opencollective", @@ -5158,9 +5207,10 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { "nanoid": "^3.3.7", - "picocolors": "^1.0.0", + "picocolors": "^1.0.1", "source-map-js": "^1.2.0" }, "engines": { @@ -5245,21 +5295,6 @@ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", "dev": true }, - "node_modules/prettier": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", - "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", - "optional": true, - "bin": { - "prettier": "bin-prettier.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -5296,12 +5331,6 @@ "node": ">= 0.10" } }, - "node_modules/pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==", - "dev": true - }, "node_modules/pug": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/pug/-/pug-3.0.2.tgz", @@ -5418,7 +5447,6 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, "engines": { "node": ">=6" } @@ -5442,7 +5470,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, "dependencies": { "safe-buffer": "^5.1.0" } @@ -5684,7 +5711,6 @@ "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, "funding": [ { "type": "github", @@ -5859,7 +5885,6 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", - "dev": true, "dependencies": { "randombytes": "^2.1.0" } @@ -6076,7 +6101,6 @@ "version": "0.5.21", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dev": true, "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" @@ -6235,6 +6259,22 @@ "node": ">=6" } }, + "node_modules/style-loader": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-4.0.0.tgz", + "integrity": "sha512-1V4WqhhZZgjVAVJyt7TdDPZoPBPNHbekX4fWnCJL1yQukhCeZhJySUL+gL9y6sNdN95uEOS83Y55SqHcP7MzLA==", + "license": "MIT", + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.27.0" + } + }, "node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -6262,7 +6302,6 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", - "dev": true, "engines": { "node": ">=6" } @@ -6271,7 +6310,6 @@ "version": "5.30.4", "resolved": "https://registry.npmjs.org/terser/-/terser-5.30.4.tgz", "integrity": "sha512-xRdd0v64a8mFK9bnsKVdoNP9GQIKUAaJPTaqEQDL4w/J8WaW4sWXXoMZ+6SimPkfT5bElreXf8m9HnmPc3E1BQ==", - "dev": true, "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.8.2", @@ -6289,7 +6327,6 @@ "version": "5.3.10", "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", - "dev": true, "dependencies": { "@jridgewell/trace-mapping": "^0.3.20", "jest-worker": "^27.4.5", @@ -6323,7 +6360,6 @@ "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -6339,7 +6375,6 @@ "version": "3.5.2", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, "peerDependencies": { "ajv": "^6.9.1" } @@ -6347,14 +6382,12 @@ "node_modules/terser-webpack-plugin/node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" }, "node_modules/terser-webpack-plugin/node_modules/schema-utils": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", - "dev": true, "dependencies": { "@types/json-schema": "^7.0.8", "ajv": "^6.12.5", @@ -6372,7 +6405,6 @@ "version": "8.11.3", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", - "dev": true, "bin": { "acorn": "bin/acorn" }, @@ -6387,11 +6419,12 @@ "dev": true }, "node_modules/tippy.js": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/tippy.js/-/tippy.js-2.6.0.tgz", - "integrity": "sha512-hBcy6UXK3epiFwpkycy7Pn1SSLofUmawpPnlYg5ginbXMc/3EX2ivjzHfjvr/WPEpUg71/7ssiovhxDtCWvL2A==", + "version": "6.3.7", + "resolved": "https://registry.npmjs.org/tippy.js/-/tippy.js-6.3.7.tgz", + "integrity": "sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ==", + "license": "MIT", "dependencies": { - "popper.js": "^1.14.3" + "@popperjs/core": "^2.9.0" } }, "node_modules/to-fast-properties": { @@ -6450,8 +6483,22 @@ "node_modules/undici-types": { "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + }, + "node_modules/unhead": { + "version": "1.9.16", + "resolved": "https://registry.npmjs.org/unhead/-/unhead-1.9.16.tgz", + "integrity": "sha512-FOoXkuRNDwt7PUaNE0LXNCb6RCz4vTpkGymz4tJ8rcaG5uUJ0lxGK536hzCFwFw3Xkp3n+tkt2yCcbAZE/FOvA==", + "license": "MIT", + "dependencies": { + "@unhead/dom": "1.9.16", + "@unhead/schema": "1.9.16", + "@unhead/shared": "1.9.16", + "hookable": "^5.5.3" + }, + "funding": { + "url": "https://github.com/sponsors/harlan-zw" + } }, "node_modules/unicode-canonical-property-names-ecmascript": { "version": "2.0.0", @@ -6506,7 +6553,6 @@ "version": "1.0.13", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", - "dev": true, "funding": [ { "type": "opencollective", @@ -6536,7 +6582,6 @@ "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, "dependencies": { "punycode": "^2.1.0" } @@ -6583,157 +6628,156 @@ } }, "node_modules/vue": { - "version": "2.7.16", - "resolved": "https://registry.npmjs.org/vue/-/vue-2.7.16.tgz", - "integrity": "sha512-4gCtFXaAA3zYZdTp5s4Hl2sozuySsgz4jy1EnpBHNfpMa9dK1ZCG7viqBPCwXtmgc8nHqUsAu3G4gtmXkkY3Sw==", - "deprecated": "Vue 2 has reached EOL and is no longer actively maintained. See https://v2.vuejs.org/eol/ for more details.", + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.4.38.tgz", + "integrity": "sha512-f0ZgN+mZ5KFgVv9wz0f4OgVKukoXtS3nwET4c2vLBGQR50aI8G0cqbFtLlX9Yiyg3LFGBitruPHt2PxwTduJEw==", + "license": "MIT", "dependencies": { - "@vue/compiler-sfc": "2.7.16", - "csstype": "^3.1.0" + "@vue/compiler-dom": "3.4.38", + "@vue/compiler-sfc": "3.4.38", + "@vue/runtime-dom": "3.4.38", + "@vue/server-renderer": "3.4.38", + "@vue/shared": "3.4.38" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/vue-hot-reload-api": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/vue-hot-reload-api/-/vue-hot-reload-api-2.3.4.tgz", - "integrity": "sha512-BXq3jwIagosjgNVae6tkHzzIk6a8MHFtzAdwhnV5VlvPTFxDCvIttgSiHWjdGoTJvXtmRu5HacExfdarRcFhog==", - "dev": true - }, "node_modules/vue-loader": { - "version": "15.11.1", - "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-15.11.1.tgz", - "integrity": "sha512-0iw4VchYLePqJfJu9s62ACWUXeSqM30SQqlIftbYWM3C+jpPcEHKSPUZBLjSF9au4HTHQ/naF6OGnO3Q/qGR3Q==", + "version": "17.4.2", + "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-17.4.2.tgz", + "integrity": "sha512-yTKOA4R/VN4jqjw4y5HrynFL8AK0Z3/Jt7eOJXEitsm0GMRHDBjCfCiuTiLP7OESvsZYo2pATCWhDqxC5ZrM6w==", "dev": true, + "license": "MIT", "dependencies": { - "@vue/component-compiler-utils": "^3.1.0", - "hash-sum": "^1.0.2", - "loader-utils": "^1.1.0", - "vue-hot-reload-api": "^2.3.0", - "vue-style-loader": "^4.1.0" + "chalk": "^4.1.0", + "hash-sum": "^2.0.0", + "watchpack": "^2.4.0" }, "peerDependencies": { - "css-loader": "*", - "webpack": "^3.0.0 || ^4.1.0 || ^5.0.0-0" + "webpack": "^4.1.0 || ^5.0.0-0" }, "peerDependenciesMeta": { - "cache-loader": { + "@vue/compiler-sfc": { "optional": true }, - "prettier": { - "optional": true - }, - "vue-template-compiler": { + "vue": { "optional": true } } }, - "node_modules/vue-loader/node_modules/json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "node_modules/vue-loader/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { - "minimist": "^1.2.0" + "color-convert": "^2.0.1" }, - "bin": { - "json5": "lib/cli.js" + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/vue-loader/node_modules/loader-utils": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz", - "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==", + "node_modules/vue-loader/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^1.0.1" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">=4.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/vue-meta": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/vue-meta/-/vue-meta-2.4.0.tgz", - "integrity": "sha512-XEeZUmlVeODclAjCNpWDnjgw+t3WA6gdzs6ENoIAgwO1J1d5p1tezDhtteLUFwcaQaTtayRrsx7GL6oXp/m2Jw==", + "node_modules/vue-loader/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", "dependencies": { - "deepmerge": "^4.2.2" + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" } }, - "node_modules/vue-router": { - "version": "3.6.5", - "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.6.5.tgz", - "integrity": "sha512-VYXZQLtjuvKxxcshuRAwjHnciqZVoXAjTjcqBTz4rKc8qih9g9pI3hbDjmqXaHdgL3v8pV6P8Z335XvHzESxLQ==" - }, - "node_modules/vue-style-loader": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/vue-style-loader/-/vue-style-loader-4.1.3.tgz", - "integrity": "sha512-sFuh0xfbtpRlKfm39ss/ikqs9AbKCoXZBpHeVZ8Tx650o0k0q/YCM7FRvigtxpACezfq6af+a7JeqVTWvncqDg==", + "node_modules/vue-loader/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true, - "dependencies": { - "hash-sum": "^1.0.2", - "loader-utils": "^1.0.2" - } + "license": "MIT" }, - "node_modules/vue-style-loader/node_modules/json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "node_modules/vue-loader/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "json5": "lib/cli.js" + "license": "MIT", + "engines": { + "node": ">=8" } }, - "node_modules/vue-style-loader/node_modules/loader-utils": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz", - "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==", + "node_modules/vue-loader/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^1.0.1" + "has-flag": "^4.0.0" }, "engines": { - "node": ">=4.0.0" + "node": ">=8" } }, - "node_modules/vue-template-compiler": { - "version": "2.7.16", - "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.7.16.tgz", - "integrity": "sha512-AYbUWAJHLGGQM7+cNTELw+KsOG9nl2CnSv467WobS5Cv9uk3wFcnr1Etsz2sEIHEZvw1U+o9mRlEO6QbZvUPGQ==", - "dev": true, + "node_modules/vue-router": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.4.3.tgz", + "integrity": "sha512-sv6wmNKx2j3aqJQDMxLFzs/u/mjA9Z5LCgy6BE0f7yFWMjrPLnS/sPNn8ARY/FXw6byV18EFutn5lTO6+UsV5A==", + "license": "MIT", "dependencies": { - "de-indent": "^1.0.2", - "he": "^1.2.0" + "@vue/devtools-api": "^6.6.3" + }, + "funding": { + "url": "https://github.com/sponsors/posva" + }, + "peerDependencies": { + "vue": "^3.2.0" } }, - "node_modules/vue-template-es2015-compiler": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz", - "integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==", - "dev": true - }, "node_modules/vue-tippy": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/vue-tippy/-/vue-tippy-2.1.3.tgz", - "integrity": "sha512-McnxRXjOKhYps/rDrji1xoOn4yIavEjuEsu7vfCjhvAaBh/YdQhLgHlkqjShhNKfWB8zA3M9bDJUC9MhfXOhdQ==", + "version": "6.4.4", + "resolved": "https://registry.npmjs.org/vue-tippy/-/vue-tippy-6.4.4.tgz", + "integrity": "sha512-0C5TSU482FvjhEeKrPkz08tzyC/KJC0CiEbm3yW9oS+n3fa03ajEzU2QcxI9oR6Hwlg8NOP0U6T4EsGuccq6YQ==", + "license": "MIT", "dependencies": { - "popper.js": "^1.14.3", - "tippy.js": "^2.6.*" + "tippy.js": "^6.3.7" }, "peerDependencies": { - "vue": "^2.5.9" + "vue": "^3.2.0" } }, "node_modules/watchpack": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.1.tgz", "integrity": "sha512-8wrBCMtVhqcXP2Sup1ctSkga6uc2Bx0IIvKyT7yTFier5AXHooSI+QyQQAtTb7+E0IUCCKyTFmXqdqgum2XWGg==", - "dev": true, "dependencies": { "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.1.2" @@ -6755,7 +6799,6 @@ "version": "5.91.0", "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.91.0.tgz", "integrity": "sha512-rzVwlLeBWHJbmgTC/8TvAcu5vpJNII+MelQpylD4jNERPwpBJOE2lEcko1zJX3QJeLjTTAnQxn/OJ8bjDzVQaw==", - "dev": true, "dependencies": { "@types/eslint-scope": "^3.7.3", "@types/estree": "^1.0.5", @@ -6958,7 +7001,6 @@ "version": "3.2.3", "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", - "dev": true, "engines": { "node": ">=10.13.0" } @@ -6967,7 +7009,6 @@ "version": "8.11.3", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", - "dev": true, "bin": { "acorn": "bin/acorn" }, @@ -6979,7 +7020,6 @@ "version": "1.9.0", "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", - "dev": true, "peerDependencies": { "acorn": "^8" } @@ -6988,7 +7028,6 @@ "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -7004,7 +7043,6 @@ "version": "3.5.2", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, "peerDependencies": { "ajv": "^6.9.1" } @@ -7012,14 +7050,12 @@ "node_modules/webpack/node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" }, "node_modules/webpack/node_modules/schema-utils": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", - "dev": true, "dependencies": { "@types/json-schema": "^7.0.8", "ajv": "^6.12.5", @@ -7250,6 +7286,15 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zhead": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/zhead/-/zhead-2.2.4.tgz", + "integrity": "sha512-8F0OI5dpWIA5IGG5NHUg9staDwz/ZPxZtvGVf01j7vHqSyZ0raHY+78atOVxRqb73AotX22uV1pXt3gYSstGag==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/harlan-zw" + } } } } diff --git a/package.json b/package.json index f95d42cd8..269c04523 100644 --- a/package.json +++ b/package.json @@ -9,15 +9,17 @@ "dev": "webpack serve", "build": "webpack --progress", "process": "cd process && npm run process", - "process-all": "cd process && npm run process -- download" + "process-all": "cd process && npm run process -- download", + "process-specific-sprites": "cd process && npm run process -- specific-sprites" }, "dependencies": { + "@vueuse/head": "^2.0.0", "lodash": "^4.17.21", "pug": "^3.0.2", - "vue": "^2.7.16", - "vue-meta": "^2.4.0", - "vue-router": "^3.6.5", - "vue-tippy": "^2.1.3" + "style-loader": "^4.0.0", + "vue": "^3.4.38", + "vue-router": "^4.4.3", + "vue-tippy": "^6.4.4" }, "browserslist": [ "> 1%", @@ -27,6 +29,7 @@ "devDependencies": { "@babel/core": "^7.24.4", "@babel/preset-env": "^7.24.4", + "@vue/compiler-sfc": "^3.4.38", "ajv": "^8.12.0", "babel-loader": "^9.1.3", "cross-env": "^7.0.3", @@ -34,8 +37,7 @@ "file-loader": "^6.2.0", "sass": "^1.75.0", "sass-loader": "^14.2.1", - "vue-loader": "^15.11.1", - "vue-template-compiler": "^2.7.16", + "vue-loader": "^17.4.2", "webpack": "^5.91.0", "webpack-cli": "^5.1.4", "webpack-dev-server": "^5.0.4" diff --git a/process/package.json b/process/package.json index e3b4d4134..24b6ffc5b 100644 --- a/process/package.json +++ b/process/package.json @@ -5,7 +5,8 @@ "main": "process.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", - "process": "npm i && node_modules/.bin/ts-node process" + "process": "node_modules/.bin/ts-node process", + "process-specific-sprites": "node_modules/.bin/ts-node process specific-sprites" }, "author": "", "license": "ISC", diff --git a/process/process.ts b/process/process.ts index 770f3cf7e..74cf7111e 100644 --- a/process/process.ts +++ b/process/process.ts @@ -8,6 +8,22 @@ import {MainProcessor} from './src/MainProcessor'; const processor = new MainProcessor(__dirname); +if (process.argv.includes('specific-sprites')) { + let objects_str = process.argv[process.argv.indexOf('specific-sprites') + 1]; + if (!objects_str) { + console.log("Please provide a comma-separated list of object IDs.") + process.exit(1); + } + let objects = objects_str.split(','); + if (objects.length === 0) { + console.error("No valid object IDs found."); + process.exit(1); + } + processor.processSpecificObjects(objects); + process.exit(0); +} + + processor.doDownload = process.argv.includes('download'); processor.doSprites = processor.doDownload || process.argv.includes('sprites'); processor.doSounds = processor.doDownload || process.argv.includes('sounds'); diff --git a/process/src/GameData.ts b/process/src/GameData.ts index dc6f1a422..c804434a5 100644 --- a/process/src/GameData.ts +++ b/process/src/GameData.ts @@ -176,6 +176,59 @@ class GameData { if (!fs.existsSync(path)) fs.mkdirSync(path); } + importSpecificObjects(ids: string[]): void { + this.eachFileContent("objects", ".txt", (content, _filename) => { + const object = new GameObject(content); + // console.log("object = ", object ? object?.id : "NULL"); + if (object.id && ids.includes(object.id)) { + this.objects[object.id] = object; + } + }); + } + + convertSpecificSpriteImages(): void { + const spriteIds :string[] = []; + + // Collect all sprite IDs from the objects + for (let id in this.objects) { + const object = this.objects[id]; + if (object.data.sprites) { + for (let i = 0; i < object.data.sprites.length; i++) { + if (!spriteIds.includes(object.data.sprites[i].id)) { + spriteIds.push(object.data.sprites[i].id); + } + } + } + } + + console.log("Converting " + spriteIds.length + " sprites for " + Object.keys(this.objects).length + " objects"); + + const dir = this.dataDir + "/sprites"; + for (let i = 0; i < spriteIds.length; i++) { + const spriteId = spriteIds[i]; + const tgaFile = `${dir}/${spriteId}.tga`; + const txtFile = `${dir}/${spriteId}.txt`; + + if (!fs.existsSync(tgaFile)) { + console.error(`Error: Missing TGA file for sprite ID ${spriteId}`); + continue; + } + + if (!fs.existsSync(txtFile)) { + console.error(`Error: Missing TXT file for sprite ID ${spriteId}`); + continue; + } + + const outPath = this.staticDir + `/sprites/sprite_${spriteId}.png`; + spawnSync("convert", [tgaFile, outPath]); + } + } + + processSpecificSprites(): void { + const processor = new SpriteProcessor(this.dataDir + "/sprites", this.staticDir + "/sprites"); + processor.process(this.objects); + } + // Allow any so we can save any object/array/value we want saveJSON(path: string, data: any): void { const minPath = this.staticDir + "/" + path; diff --git a/process/src/GameObject.ts b/process/src/GameObject.ts index 9973d3038..57ca3a2f3 100644 --- a/process/src/GameObject.ts +++ b/process/src/GameObject.ts @@ -116,7 +116,6 @@ class GameObject { || data.includes("invisHolding") || data.includes("invisCont") || data.includes("spritesDrawnBehind") - || data.includes("spritesAdditiveBlend") || data.includes("ignoredCont") ) { return true; diff --git a/process/src/MainProcessor.ts b/process/src/MainProcessor.ts index 0a1030a62..58ce1d79e 100644 --- a/process/src/MainProcessor.ts +++ b/process/src/MainProcessor.ts @@ -27,7 +27,29 @@ class MainProcessor { return process.env.ONETECH_PROCESS_GIT_URL || "https://github.com/twohoursonelife/OneLifeData7.git"; } - process(version: ChangeLogVersion): ChangeLogVersion { + processSpecificObjects(ids: string[]): void { + const gameData = new GameData(this.processDir, this.dataDir(), this.staticDir(false)); + console.time("Processing specific objects took"); + + console.log("\nImporting specific objects..."); + console.time("Importing specific objects took"); + gameData.importSpecificObjects(ids); + console.timeEnd("Importing specific objects took"); + + console.log("\nConverting specific sprite images..."); + console.time("Converting specific sprite images took"); + gameData.convertSpecificSpriteImages(); + console.timeEnd("Converting specific sprite images took"); + + console.log("\nProcessing specific sprites..."); + console.time("Processing specific sprites took"); + gameData.processSpecificSprites(); + console.timeEnd("Processing specific sprites took"); + + console.timeEnd("Processing specific objects took"); + } + + process(version: ChangeLogVersion | null): ChangeLogVersion { // double-equals used to cover undefined case too. const gameData = new GameData(this.processDir, this.dataDir(), this.staticDir(version == null)); console.time("Processing took"); diff --git a/process/src/Sprite.ts b/process/src/Sprite.ts index 679755fe8..e2f08805a 100644 --- a/process/src/Sprite.ts +++ b/process/src/Sprite.ts @@ -26,7 +26,6 @@ class Sprite { parent: number; invisCont: number; spritesDrawnBehind: number[]; - spritesAdditiveBlend: number[]; ignoredCont: number[]; constructor(lines: string[], index: number, object: GameObject) { @@ -88,8 +87,6 @@ class Sprite { this.invisCont = parseInt(values[0]); } else if (attribute === "spritesDrawnBehind") { this.spritesDrawnBehind = values.map(v => parseInt(v)); - } else if (attribute === "spritesAdditiveBlend") { - this.spritesAdditiveBlend = values.map(v => parseInt(v)); } else if (attribute === "ignoredCont") { this.ignoredCont = values.map(v => parseInt(v)); } else { diff --git a/src/App.vue b/src/App.vue index 5ec3e7177..18bbfb30e 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,13 +1,12 @@ - diff --git a/src/components/BiomeImage.vue b/src/components/BiomeImage.vue index 1a11426f2..0ea7fd2cd 100644 --- a/src/components/BiomeImage.vue +++ b/src/components/BiomeImage.vue @@ -1,19 +1,25 @@ diff --git a/src/components/ObjectBrowser.vue b/src/components/ObjectBrowser.vue index afc639ded..06dc929a3 100644 --- a/src/components/ObjectBrowser.vue +++ b/src/components/ObjectBrowser.vue @@ -1,8 +1,8 @@ diff --git a/src/components/ObjectView.vue b/src/components/ObjectView.vue index a048912fd..7b8993953 100644 --- a/src/components/ObjectView.vue +++ b/src/components/ObjectView.vue @@ -1,63 +1,88 @@