Commit 82eb4be8 authored by nanahira's avatar nanahira

load cdb in another thread

parent 86d30310
Pipeline #43366 passed with stages
in 3 minutes and 13 seconds
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
"typeorm": "^0.3.28", "typeorm": "^0.3.28",
"ws": "^8.19.0", "ws": "^8.19.0",
"yaml": "^2.8.2", "yaml": "^2.8.2",
"ygopro-cdb-encode": "^1.0.4", "ygopro-cdb-encode": "^1.0.5",
"ygopro-deck-encode": "^1.0.15", "ygopro-deck-encode": "^1.0.15",
"ygopro-lflist-encode": "^1.0.3", "ygopro-lflist-encode": "^1.0.3",
"ygopro-msg-encode": "^1.1.31", "ygopro-msg-encode": "^1.1.31",
...@@ -84,7 +84,6 @@ ...@@ -84,7 +84,6 @@
"integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@babel/code-frame": "^7.29.0", "@babel/code-frame": "^7.29.0",
"@babel/generator": "^7.29.0", "@babel/generator": "^7.29.0",
...@@ -575,7 +574,6 @@ ...@@ -575,7 +574,6 @@
"resolved": "https://registry.npmjs.org/@cordisjs/core/-/core-3.18.1.tgz", "resolved": "https://registry.npmjs.org/@cordisjs/core/-/core-3.18.1.tgz",
"integrity": "sha512-yRuATOamFxeD1ztE2L3o1SaHuT2zw5DTXijQYxt9azVNeILbvtomfGG6sLZegrynJO9XZbNvXbOlQ7LBJDOlAg==", "integrity": "sha512-yRuATOamFxeD1ztE2L3o1SaHuT2zw5DTXijQYxt9azVNeILbvtomfGG6sLZegrynJO9XZbNvXbOlQ7LBJDOlAg==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"cosmokit": "^1.6.2" "cosmokit": "^1.6.2"
} }
...@@ -612,7 +610,6 @@ ...@@ -612,7 +610,6 @@
"resolved": "https://registry.npmjs.org/@cordisjs/plugin-http/-/plugin-http-0.6.3.tgz", "resolved": "https://registry.npmjs.org/@cordisjs/plugin-http/-/plugin-http-0.6.3.tgz",
"integrity": "sha512-kmw4G1t39ZZzFGpBKUNuTv2aefEUtxa1e4qu4+bTrM5Z8uYHTRzPpyJfkj9zuZwopP/Vz271OUr2UfDN5lrJKQ==", "integrity": "sha512-kmw4G1t39ZZzFGpBKUNuTv2aefEUtxa1e4qu4+bTrM5Z8uYHTRzPpyJfkj9zuZwopP/Vz271OUr2UfDN5lrJKQ==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"cosmokit": "^1.6.3", "cosmokit": "^1.6.3",
"file-type": "^16.5.4", "file-type": "^16.5.4",
...@@ -1468,7 +1465,6 @@ ...@@ -1468,7 +1465,6 @@
"resolved": "https://registry.npmjs.org/@koishijs/core/-/core-4.18.10.tgz", "resolved": "https://registry.npmjs.org/@koishijs/core/-/core-4.18.10.tgz",
"integrity": "sha512-P2dc9EqoMasqqdUz3iKyGbcd0krAG7dMT7Ju6CqrzAobj0w7i548cCE89mD3qTzhvdTKzbf4UBYDRg21lXrb4A==", "integrity": "sha512-P2dc9EqoMasqqdUz3iKyGbcd0krAG7dMT7Ju6CqrzAobj0w7i548cCE89mD3qTzhvdTKzbf4UBYDRg21lXrb4A==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@koishijs/i18n-utils": "^1.0.1", "@koishijs/i18n-utils": "^1.0.1",
"@koishijs/utils": "^7.2.1", "@koishijs/utils": "^7.2.1",
...@@ -2122,7 +2118,6 @@ ...@@ -2122,7 +2118,6 @@
"integrity": "sha512-4z2nCSBfVIMnbuu8uinj+f0o4qOeggYJLbjpPHka3KH1om7e+H9yLKTYgksTaHcGco+NClhhY2vyO3HsMH1RGw==", "integrity": "sha512-4z2nCSBfVIMnbuu8uinj+f0o4qOeggYJLbjpPHka3KH1om7e+H9yLKTYgksTaHcGco+NClhhY2vyO3HsMH1RGw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@typescript-eslint/scope-manager": "8.55.0", "@typescript-eslint/scope-manager": "8.55.0",
"@typescript-eslint/types": "8.55.0", "@typescript-eslint/types": "8.55.0",
...@@ -2628,7 +2623,6 @@ ...@@ -2628,7 +2623,6 @@
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"bin": { "bin": {
"acorn": "bin/acorn" "acorn": "bin/acorn"
}, },
...@@ -3024,7 +3018,6 @@ ...@@ -3024,7 +3018,6 @@
} }
], ],
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"baseline-browser-mapping": "^2.9.0", "baseline-browser-mapping": "^2.9.0",
"caniuse-lite": "^1.0.30001759", "caniuse-lite": "^1.0.30001759",
...@@ -3479,7 +3472,6 @@ ...@@ -3479,7 +3472,6 @@
"resolved": "https://registry.npmjs.org/cordis/-/cordis-3.18.1.tgz", "resolved": "https://registry.npmjs.org/cordis/-/cordis-3.18.1.tgz",
"integrity": "sha512-9IbthFbFBVJ15WBDNPqHdl59TyEAMNWxF1Dxsdi14625ePQkMX35WvcqgGno0BcXlpXDbUaBZgQ+jfBYT+uuSQ==", "integrity": "sha512-9IbthFbFBVJ15WBDNPqHdl59TyEAMNWxF1Dxsdi14625ePQkMX35WvcqgGno0BcXlpXDbUaBZgQ+jfBYT+uuSQ==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@cordisjs/core": "3.18.1", "@cordisjs/core": "3.18.1",
"@cordisjs/loader": "^0.13.1", "@cordisjs/loader": "^0.13.1",
...@@ -3900,7 +3892,6 @@ ...@@ -3900,7 +3892,6 @@
"deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.6.1", "@eslint-community/regexpp": "^4.6.1",
...@@ -3957,7 +3948,6 @@ ...@@ -3957,7 +3948,6 @@
"integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==", "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"bin": { "bin": {
"eslint-config-prettier": "bin/cli.js" "eslint-config-prettier": "bin/cli.js"
}, },
...@@ -4951,7 +4941,6 @@ ...@@ -4951,7 +4941,6 @@
"resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.9.2.tgz", "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.9.2.tgz",
"integrity": "sha512-tAAg/72/VxOUW7RQSX1pIxJVucYKcjFjfvj60L57jrZpYCHC3XN0WCQ3sNYL4Gmvv+7GPvTAjc+KSdeNuE8oWQ==", "integrity": "sha512-tAAg/72/VxOUW7RQSX1pIxJVucYKcjFjfvj60L57jrZpYCHC3XN0WCQ3sNYL4Gmvv+7GPvTAjc+KSdeNuE8oWQ==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@ioredis/commands": "1.5.0", "@ioredis/commands": "1.5.0",
"cluster-key-slot": "^1.1.0", "cluster-key-slot": "^1.1.0",
...@@ -5239,7 +5228,6 @@ ...@@ -5239,7 +5228,6 @@
"integrity": "sha512-F26gjC0yWN8uAA5m5Ss8ZQf5nDHWGlN/xWZIh8S5SRbsEKBovwZhxGd6LJlbZYxBgCYOtreSUyb8hpXyGC5O4A==", "integrity": "sha512-F26gjC0yWN8uAA5m5Ss8ZQf5nDHWGlN/xWZIh8S5SRbsEKBovwZhxGd6LJlbZYxBgCYOtreSUyb8hpXyGC5O4A==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@jest/core": "30.2.0", "@jest/core": "30.2.0",
"@jest/types": "30.2.0", "@jest/types": "30.2.0",
...@@ -6033,7 +6021,6 @@ ...@@ -6033,7 +6021,6 @@
"resolved": "https://registry.npmjs.org/koishi/-/koishi-4.18.10.tgz", "resolved": "https://registry.npmjs.org/koishi/-/koishi-4.18.10.tgz",
"integrity": "sha512-rEbF2NuHDAsBJ0+5B12RsRk7QWM/1sZvMnlaSj2TqUP+558Z1+lVZO9HhsyxrEp+r+bheRNfpJDN8aO369/myg==", "integrity": "sha512-rEbF2NuHDAsBJ0+5B12RsRk7QWM/1sZvMnlaSj2TqUP+558Z1+lVZO9HhsyxrEp+r+bheRNfpJDN8aO369/myg==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@koishijs/core": "4.18.10", "@koishijs/core": "4.18.10",
"@koishijs/loader": "4.6.10", "@koishijs/loader": "4.6.10",
...@@ -6703,7 +6690,6 @@ ...@@ -6703,7 +6690,6 @@
"resolved": "https://registry.npmjs.org/pg/-/pg-8.18.0.tgz", "resolved": "https://registry.npmjs.org/pg/-/pg-8.18.0.tgz",
"integrity": "sha512-xqrUDL1b9MbkydY/s+VZ6v+xiMUmOUk7SS9d/1kpyQxoJ6U9AO1oIJyUWVZojbfe5Cc/oluutcgFG4L9RDP1iQ==", "integrity": "sha512-xqrUDL1b9MbkydY/s+VZ6v+xiMUmOUk7SS9d/1kpyQxoJ6U9AO1oIJyUWVZojbfe5Cc/oluutcgFG4L9RDP1iQ==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"pg-connection-string": "^2.11.0", "pg-connection-string": "^2.11.0",
"pg-pool": "^3.11.0", "pg-pool": "^3.11.0",
...@@ -7024,7 +7010,6 @@ ...@@ -7024,7 +7010,6 @@
"integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"bin": { "bin": {
"prettier": "bin/prettier.cjs" "prettier": "bin/prettier.cjs"
}, },
...@@ -8274,7 +8259,6 @@ ...@@ -8274,7 +8259,6 @@
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"engines": { "engines": {
"node": ">=12" "node": ">=12"
}, },
...@@ -8539,7 +8523,6 @@ ...@@ -8539,7 +8523,6 @@
"resolved": "https://registry.npmjs.org/typed-struct/-/typed-struct-2.7.1.tgz", "resolved": "https://registry.npmjs.org/typed-struct/-/typed-struct-2.7.1.tgz",
"integrity": "sha512-GluzA9kYlHjATJmzBDA2X9G9237Md5zsJsc8uEkmpvUFeuUvt+e7Sq11/nQnVB2VZIfKNR1CrwTCgpJVz52pAA==", "integrity": "sha512-GluzA9kYlHjATJmzBDA2X9G9237Md5zsJsc8uEkmpvUFeuUvt+e7Sq11/nQnVB2VZIfKNR1CrwTCgpJVz52pAA==",
"license": "MIT", "license": "MIT",
"peer": true,
"engines": { "engines": {
"node": ">=12" "node": ">=12"
}, },
...@@ -8674,7 +8657,6 @@ ...@@ -8674,7 +8657,6 @@
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
"dev": true, "dev": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"peer": true,
"bin": { "bin": {
"tsc": "bin/tsc", "tsc": "bin/tsc",
"tsserver": "bin/tsserver" "tsserver": "bin/tsserver"
...@@ -9126,9 +9108,9 @@ ...@@ -9126,9 +9108,9 @@
} }
}, },
"node_modules/ygopro-cdb-encode": { "node_modules/ygopro-cdb-encode": {
"version": "1.0.4", "version": "1.0.5",
"resolved": "https://registry.npmjs.org/ygopro-cdb-encode/-/ygopro-cdb-encode-1.0.4.tgz", "resolved": "https://registry.npmjs.org/ygopro-cdb-encode/-/ygopro-cdb-encode-1.0.5.tgz",
"integrity": "sha512-951ab8yrhmc69EbIqRSumRKbsI1D8OiDpiG37Ws5gQAjRvJsx8d0BOYoAgLrjadOdBtl+UUhJyk4pWpSCp9Z+w==", "integrity": "sha512-WnhMJTdXWZxZtcW8OnfxxbCEHehuYByrqyZXnyQ739422CcZks7ulVIlb2pdn1D8EeWb2kQxnxBoMzX/4g/+3g==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@types/sql.js": "^1.4.9", "@types/sql.js": "^1.4.9",
......
...@@ -70,7 +70,7 @@ ...@@ -70,7 +70,7 @@
"typeorm": "^0.3.28", "typeorm": "^0.3.28",
"ws": "^8.19.0", "ws": "^8.19.0",
"yaml": "^2.8.2", "yaml": "^2.8.2",
"ygopro-cdb-encode": "^1.0.4", "ygopro-cdb-encode": "^1.0.5",
"ygopro-deck-encode": "^1.0.15", "ygopro-deck-encode": "^1.0.15",
"ygopro-lflist-encode": "^1.0.3", "ygopro-lflist-encode": "^1.0.3",
"ygopro-msg-encode": "^1.1.31", "ygopro-msg-encode": "^1.1.31",
...@@ -91,4 +91,4 @@ ...@@ -91,4 +91,4 @@
"ts-jest": "^29.4.6", "ts-jest": "^29.4.6",
"typescript": "^5.9.3" "typescript": "^5.9.3"
} }
} }
\ No newline at end of file
...@@ -8,7 +8,8 @@ export class OcgcoreWorkerOptions { ...@@ -8,7 +8,8 @@ export class OcgcoreWorkerOptions {
extraScriptPaths: string[]; extraScriptPaths: string[];
@TransportType(() => CardStorage) @TransportType(() => CardStorage)
cardStorage: CardStorage; cardStorage: CardStorage;
ocgcoreWasmPath?: string; @TransportType(() => Buffer)
ocgcoreWasmBinary?: Buffer;
seed: number[]; seed: number[];
hostinfo: HostInfo; hostinfo: HostInfo;
@TransportType(() => [YGOProDeck]) @TransportType(() => [YGOProDeck])
......
...@@ -35,7 +35,6 @@ import { ...@@ -35,7 +35,6 @@ import {
YGOProMsgResponseBase, YGOProMsgResponseBase,
YGOProMsgRetry, YGOProMsgRetry,
} from 'ygopro-msg-encode'; } from 'ygopro-msg-encode';
import * as fs from 'node:fs';
const { OcgcoreScriptConstants } = _OcgcoreConstants; const { OcgcoreScriptConstants } = _OcgcoreConstants;
const OCGCORE_MESSAGE_REPLAY_BUFFER_SIZE = 128; const OCGCORE_MESSAGE_REPLAY_BUFFER_SIZE = 128;
...@@ -95,10 +94,7 @@ export class OcgcoreWorker { ...@@ -95,10 +94,7 @@ export class OcgcoreWorker {
@WorkerInit() @WorkerInit()
async init() { async init() {
let wasmBinary: Uint8Array | undefined; const wasmBinary = this.options.ocgcoreWasmBinary;
if (this.options.ocgcoreWasmPath) {
wasmBinary = await fs.promises.readFile(this.options.ocgcoreWasmPath);
}
// Create ocgcore wrapper // Create ocgcore wrapper
this.ocgcore = await createOcgcoreWrapper( this.ocgcore = await createOcgcoreWrapper(
......
...@@ -62,9 +62,9 @@ export class RoomEventRegister { ...@@ -62,9 +62,9 @@ export class RoomEventRegister {
continue; continue;
} }
clientParamIndex = fallbackClientIndex; clientParamIndex = fallbackClientIndex;
this.logger.warn( // this.logger.warn(
`Method ${method} has no explicit Client param metadata, fallback to arg[${clientParamIndex}] for client`, // `Method ${method} has no explicit Client param metadata, fallback to arg[${clientParamIndex}] for client`,
); // );
} }
// 获取方法选项 // 获取方法选项
......
...@@ -98,7 +98,6 @@ import { getMessageIdentifier } from '../utility/get-message-identifier'; ...@@ -98,7 +98,6 @@ import { getMessageIdentifier } from '../utility/get-message-identifier';
import { canIncreaseTime } from '../utility/can-increase-time'; import { canIncreaseTime } from '../utility/can-increase-time';
import { TimerState } from './timer-state'; import { TimerState } from './timer-state';
import { makeArray } from 'aragami/dist/src/utility/utility'; import { makeArray } from 'aragami/dist/src/utility/utility';
import path from 'path';
import { OnRoomCreate } from './room-event/on-room-create'; import { OnRoomCreate } from './room-event/on-room-create';
import { OnRoomFinalize } from './room-event/on-room-finalize'; import { OnRoomFinalize } from './room-event/on-room-finalize';
import { OnRoomSidingStart } from './room-event/on-room-siding-start'; import { OnRoomSidingStart } from './room-event/on-room-siding-start';
...@@ -1349,12 +1348,8 @@ export class Room { ...@@ -1349,12 +1348,8 @@ export class Room {
'Initializing OCGCoreWorker', 'Initializing OCGCoreWorker',
); );
const ocgcoreWasmPathConfig =
this.ctx.config.getString('OCGCORE_WASM_PATH');
const ocgcoreWasmPath = ocgcoreWasmPathConfig
? path.resolve(process.cwd(), ocgcoreWasmPathConfig)
: undefined;
const cardStorage = await this.resourceLoader.getCardStorage(); const cardStorage = await this.resourceLoader.getCardStorage();
const ocgcoreWasmBinary = await this.resourceLoader.getOcgcoreWasmBinary();
try { try {
this.ocgcore = await initWorker(OcgcoreWorker, { this.ocgcore = await initWorker(OcgcoreWorker, {
...@@ -1363,7 +1358,7 @@ export class Room { ...@@ -1363,7 +1358,7 @@ export class Room {
ygoproPaths: this.resourceLoader.ygoproPaths, ygoproPaths: this.resourceLoader.ygoproPaths,
extraScriptPaths, extraScriptPaths,
cardStorage, cardStorage,
ocgcoreWasmPath, ocgcoreWasmBinary,
registry, registry,
decks: duelRecord.toSwappedPlayers().map((p) => p.deck), decks: duelRecord.toSwappedPlayers().map((p) => p.deck),
}); });
......
import * as fs from 'node:fs';
import { searchYGOProResource } from 'koishipro-core.js';
import type { CardDataEntry } from 'ygopro-cdb-encode';
import { YGOProCdb } from 'ygopro-cdb-encode';
import initSqlJs from 'sql.js';
import { DefineWorker, TransportType, WorkerMethod, toShared } from 'yuzuthread';
import { CardStorage } from './card-storage';
const isFileNotFoundError = (error: unknown): error is NodeJS.ErrnoException =>
typeof error === 'object' &&
error !== null &&
'code' in error &&
(error as NodeJS.ErrnoException).code === 'ENOENT';
export class CardLoadWorkerResult {
@TransportType(() => CardStorage)
cardStorage: CardStorage;
dbCount: number;
failedFiles: string[];
@TransportType(() => Buffer)
ocgcoreWasmBinary?: Buffer;
}
@DefineWorker()
export class CardLoadWorker {
constructor(
private ygoproPaths: string[],
private ocgcoreWasmPath?: string,
) {}
@WorkerMethod()
@TransportType(() => CardLoadWorkerResult)
async load(): Promise<CardLoadWorkerResult> {
const SQL = await initSqlJs();
const cards: CardDataEntry[] = [];
const seen = new Set<number>();
let dbCount = 0;
const failedFiles: string[] = [];
for await (const file of searchYGOProResource(...this.ygoproPaths)) {
if (!file.path.endsWith('.cdb')) {
continue;
}
try {
const currentDb = new SQL.Database(await file.read());
try {
const currentCdb = new YGOProCdb(currentDb).noTexts();
for (const card of currentCdb.step()) {
const cardId = (card.code ?? 0) >>> 0;
if (cardId === 0 || seen.has(cardId)) {
continue;
}
seen.add(cardId);
cards.push(card);
}
++dbCount;
} finally {
currentDb.close();
}
} catch (error) {
failedFiles.push(`${file.path}: ${error}`);
continue;
}
}
let ocgcoreWasmBinary: Buffer | undefined;
if (this.ocgcoreWasmPath) {
try {
const wasmBinary = await fs.promises.readFile(this.ocgcoreWasmPath);
ocgcoreWasmBinary = toShared(wasmBinary);
} catch (error) {
if (!isFileNotFoundError(error)) {
throw error;
}
}
}
const result = new CardLoadWorkerResult();
result.cardStorage = toShared(CardStorage.fromCards(cards));
result.dbCount = dbCount;
result.failedFiles = failedFiles;
result.ocgcoreWasmBinary = ocgcoreWasmBinary;
return result;
}
}
...@@ -3,11 +3,10 @@ import type { CardReaderFn } from 'koishipro-core.js'; ...@@ -3,11 +3,10 @@ import type { CardReaderFn } from 'koishipro-core.js';
import { searchYGOProResource } from 'koishipro-core.js'; import { searchYGOProResource } from 'koishipro-core.js';
import { YGOProLFList } from 'ygopro-lflist-encode'; import { YGOProLFList } from 'ygopro-lflist-encode';
import path from 'node:path'; import path from 'node:path';
import type { CardDataEntry } from 'ygopro-cdb-encode'; import { runInWorker } from 'yuzuthread';
import { YGOProCdb } from 'ygopro-cdb-encode';
import { toShared } from 'yuzuthread';
import BetterLock from 'better-lock'; import BetterLock from 'better-lock';
import { CardStorage } from './card-storage'; import { CardStorage } from './card-storage';
import { CardLoadWorker } from './card-load-worker';
export class YGOProResourceLoader { export class YGOProResourceLoader {
constructor(private ctx: Context) { constructor(private ctx: Context) {
...@@ -27,6 +26,7 @@ export class YGOProResourceLoader { ...@@ -27,6 +26,7 @@ export class YGOProResourceLoader {
private loadingCardStorage?: Promise<CardStorage>; private loadingCardStorage?: Promise<CardStorage>;
private currentCardStorage?: CardStorage; private currentCardStorage?: CardStorage;
private currentCardReader?: CardReaderFn; private currentCardReader?: CardReaderFn;
private currentOcgcoreWasmBinary?: Buffer;
async getCardStorage() { async getCardStorage() {
if (this.currentCardStorage) { if (this.currentCardStorage) {
...@@ -48,6 +48,11 @@ export class YGOProResourceLoader { ...@@ -48,6 +48,11 @@ export class YGOProResourceLoader {
return reader; return reader;
} }
async getOcgcoreWasmBinary() {
await this.getCardStorage();
return this.currentOcgcoreWasmBinary;
}
async loadYGOProCdbs() { async loadYGOProCdbs() {
if (this.loadingCardStorage) { if (this.loadingCardStorage) {
return this.loadingCardStorage; return this.loadingCardStorage;
...@@ -69,45 +74,30 @@ export class YGOProResourceLoader { ...@@ -69,45 +74,30 @@ export class YGOProResourceLoader {
} }
private async loadCardStorage() { private async loadCardStorage() {
const cards: CardDataEntry[] = []; const ocgcoreWasmPathConfig =
const seen = new Set<number>(); this.ctx.config.getString('OCGCORE_WASM_PATH');
let dbCount = 0; const ocgcoreWasmPath = ocgcoreWasmPathConfig
? path.resolve(process.cwd(), ocgcoreWasmPathConfig)
: undefined;
const { cardStorage, dbCount, failedFiles, ocgcoreWasmBinary } =
await runInWorker(
CardLoadWorker,
(worker) => worker.load(),
this.ygoproPaths,
ocgcoreWasmPath,
);
for await (const file of searchYGOProResource(...this.ygoproPaths)) { this.currentOcgcoreWasmBinary = ocgcoreWasmBinary;
const filename = path.basename(file.path); for (const failedFile of failedFiles) {
if (!filename?.endsWith('.cdb')) { this.logger.warn(`Failed to read ${failedFile}`);
continue;
}
try {
const currentDb = new this.ctx.SQL.Database(await file.read());
try {
const currentCdb = new YGOProCdb(currentDb).noTexts();
for (const card of currentCdb.find()) {
const cardId = card.code >>> 0;
if (seen.has(cardId)) {
continue;
}
seen.add(cardId);
cards.push(card);
}
++dbCount;
} finally {
currentDb.close();
}
} catch (e) {
this.logger.warn(`Failed to read ${file.path}: ${e}`);
continue;
}
} }
const storage = toShared(CardStorage.fromCards(cards));
this.logger.info( this.logger.info(
{ {
size: storage.byteLength, size: cardStorage.byteLength,
}, },
`Merged database from ${dbCount} databases with ${storage.size} cards`, `Merged database from ${dbCount} databases with ${cardStorage.size} cards`,
); );
return storage; return cardStorage;
} }
async *getLFLists() { async *getLFLists() {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment