diff --git a/package.json b/package.json index e0cbe44..9e2b46b 100644 --- a/package.json +++ b/package.json @@ -27,8 +27,9 @@ "@types/node": "^22.5.4", "blockbench-types": "^4.6.1", "rollup": "^4.21.2", - "rollup-plugin-vue": "6.0.0", - "vue-template-compiler": "latest" + "rollup-plugin-vue": "5.1.9", + "vue": "2.7.16", + "vue-template-compiler": "2.7.16" }, "dependencies": { "json5": "^2.2.3" diff --git a/rollup.config.js b/rollup.config.js index 371af7b..318a312 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -5,6 +5,30 @@ import terser from "@rollup/plugin-terser"; import image from "@rollup/plugin-image"; import vue from "rollup-plugin-vue"; +function injectVueStyles() { + return { + name: "inject-vue-styles", + transform(code, id) { + if (!id.includes(".vue?vue&type=style")) { + return null; + } + return { + code: ` +const css = ${JSON.stringify(code)}; +if (typeof document !== "undefined" && css) { + const style = document.createElement("style"); + style.setAttribute("data-plugin", "ysm-utils"); + style.textContent = css; + document.head.appendChild(style); +} +export default css; +`, + map: {mappings: ""} + }; + } + }; +} + export default { input: "src/index.js", output: { @@ -13,6 +37,7 @@ export default { }, plugins: [ vue(), + injectVueStyles(), json(), resolve(), commonjs(), @@ -22,4 +47,4 @@ export default { image() ], external: ["path"] -}; \ No newline at end of file +}; diff --git a/src/create/create_default.js b/src/create/create_default.js index e3fee73..864c421 100644 --- a/src/create/create_default.js +++ b/src/create/create_default.js @@ -1,5 +1,4 @@ import {join} from "path"; -import {mkdirSync} from "fs"; import armAnimationJson from "../../assets/default/animations/arm.animation.json"; import arrowAnimationJson from "../../assets/default/animations/arrow.animation.json"; import boatAnimationJson from "../../assets/default/animations/boat.animation.json"; @@ -56,16 +55,16 @@ function createAllFiles(selectFilePaths, formResult) { let lang = join(packPath, "lang"); let gui = join(textures, "gui"); - mkdirSync(packPath, {recursive: true}); - mkdirSync(animations, {recursive: true}); - mkdirSync(avatar, {recursive: true}); - mkdirSync(models, {recursive: true}); - mkdirSync(textures, {recursive: true}); - mkdirSync(sounds, {recursive: true}); - mkdirSync(controller, {recursive: true}); - mkdirSync(functions, {recursive: true}); - mkdirSync(lang, {recursive: true}); - mkdirSync(gui, {recursive: true}); + fs.mkdirSync(packPath, {recursive: true}); + fs.mkdirSync(animations, {recursive: true}); + fs.mkdirSync(avatar, {recursive: true}); + fs.mkdirSync(models, {recursive: true}); + fs.mkdirSync(textures, {recursive: true}); + fs.mkdirSync(sounds, {recursive: true}); + fs.mkdirSync(controller, {recursive: true}); + fs.mkdirSync(functions, {recursive: true}); + fs.mkdirSync(lang, {recursive: true}); + fs.mkdirSync(gui, {recursive: true}); // 复制文件 fs.writeFileSync(join(animations, "arm.animation.json"), autoStringify(armAnimationJson)); @@ -153,4 +152,4 @@ export var createDefaultModel = new Action("ysm_utils.create_default_model", { openDialog(selectFilePaths); } } -}); \ No newline at end of file +}); diff --git a/src/import/old_version_transform.js b/src/import/old_version_transform.js index 579ff1f..86c80ff 100644 --- a/src/import/old_version_transform.js +++ b/src/import/old_version_transform.js @@ -1,5 +1,4 @@ import {join} from "path"; -import {copyFileSync, mkdirSync} from "fs"; function basicFileGeneration(destPackPath, srcPackPath) { // 生成文件夹 @@ -8,11 +7,11 @@ function basicFileGeneration(destPackPath, srcPackPath) { let modelsPath = join(destPackPath, "models"); let texturesPath = join(destPackPath, "textures"); - mkdirSync(destPackPath, {recursive: true}); - mkdirSync(animationsPath, {recursive: true}); - mkdirSync(avatarsPath, {recursive: true}); - mkdirSync(modelsPath, {recursive: true}); - mkdirSync(texturesPath, {recursive: true}); + fs.mkdirSync(destPackPath, {recursive: true}); + fs.mkdirSync(animationsPath, {recursive: true}); + fs.mkdirSync(avatarsPath, {recursive: true}); + fs.mkdirSync(modelsPath, {recursive: true}); + fs.mkdirSync(texturesPath, {recursive: true}); // 复制动画文件 copyFile(srcPackPath, "main.animation.json", animationsPath); @@ -134,7 +133,7 @@ function copyFile(srcPath, srcFileName, destPath) { let srcFilePath = join(srcPath, srcFileName); if (fs.existsSync(srcFilePath)) { let destFilePath = join(destPath, srcFileName); - copyFileSync(srcFilePath, destFilePath); + fs.copyFileSync(srcFilePath, destFilePath); } } @@ -206,4 +205,4 @@ export function oldVersionTransform(srcPackPath, destPath, isVersion114) { Blockbench.showQuickMessage(tl("menu.ysm_utils.old_version_transform.success") + destPackPath, 3000); // 返回生成的文件夹路径 return destPackPath; -} \ No newline at end of file +} diff --git a/src/index.js b/src/index.js index a5ab89a..0c92fbb 100644 --- a/src/index.js +++ b/src/index.js @@ -5,6 +5,7 @@ import {currentInfoMenuAction} from "./menu/current_info_menu.js"; import {directImportMenuAction} from "./menu/direct_import.js"; import {createDefaultModel} from "./create/create_default.js"; import {addYsmMolang} from "./molang/ysm_molang.js"; +import {initNativeApiCompat} from "./util/native_api_compat.js"; BBPlugin.register(packageInfo.name, { title: packageInfo.title, @@ -31,6 +32,7 @@ BBPlugin.register(packageInfo.name, { }); function doLoadEvent() { + initNativeApiCompat(); loadI18n(); initCacheYsmFoldersAction(); addYsmMolang(); @@ -41,4 +43,4 @@ function doLoadEvent() { CACHE_YSM_INFO_ACTION, ]); MenuBar.update(); -} \ No newline at end of file +} diff --git a/src/util/native_api_compat.js b/src/util/native_api_compat.js new file mode 100644 index 0000000..7eb5dbb --- /dev/null +++ b/src/util/native_api_compat.js @@ -0,0 +1,80 @@ +function getNativeRequire() { + if (typeof requireNativeModule === "function") { + return requireNativeModule; + } +} + +function requireNativeApi(moduleName, options = {}) { + const nativeRequire = getNativeRequire(); + if (!nativeRequire) { + return; + } + try { + return nativeRequire(moduleName, options); + } catch (err) { + if (moduleName.startsWith("node:")) { + console.warn(`[YSM Utils] Failed to require native API "${moduleName}".`, err); + return; + } + try { + return nativeRequire(`node:${moduleName}`, options); + } catch (nodeErr) { + console.warn(`[YSM Utils] Failed to require native API "${moduleName}".`, nodeErr); + } + } +} + +function unwrapDialogOptions(args) { + return args.length > 1 ? args[1] : args[0]; +} + +function createDialogCompat(dialogApi) { + return new Proxy(dialogApi, { + get(target, property) { + const value = target[property]; + if (typeof value !== "function") { + return value; + } + return (...args) => value(unwrapDialogOptions(args)); + } + }); +} + +export function initNativeApiCompat() { + if (!globalThis.fs) { + globalThis.fs = requireNativeApi("fs", { + optional: false, + message: "YSM Utils needs file system access to read, edit, import, export, and convert YSM model packs." + }); + } + + if (!globalThis.process) { + globalThis.process = requireNativeApi("process", { + optional: false, + message: "YSM Utils needs platform information to compare file paths correctly." + }); + } + + const dialogApi = globalThis.electron?.dialog ? undefined : requireNativeApi("dialog", { + optional: false, + message: "YSM Utils needs native dialogs so you can choose YSM model folders and files." + }); + const shellApi = globalThis.electron?.shell ? undefined : requireNativeApi("shell", { + optional: false, + message: "YSM Utils needs shell access to open folders and move replaced files to the trash." + }); + + if (dialogApi || shellApi) { + globalThis.electron = { + ...(globalThis.electron ?? {}), + ...(dialogApi ? {dialog: createDialogCompat(dialogApi)} : {}), + ...(shellApi ? {shell: shellApi} : {}) + }; + } + + globalThis.currentwindow ??= null; + + if (!globalThis.fs || !globalThis.electron?.dialog || !globalThis.electron?.shell || !globalThis.process) { + throw new Error("YSM Utils cannot load because required Blockbench native API permissions were not granted."); + } +}