diff --git a/src/env.ts b/src/env.ts index e246b29..65d4811 100644 --- a/src/env.ts +++ b/src/env.ts @@ -15,8 +15,10 @@ type EditorVersion = '1.0' | '2.0' | 'unknown'; class Map { id: bigint = 0n; editorTable: EditorManager; + scriptUri: vscode.Uri; constructor(public name: string, public uri: vscode.Uri) { this.editorTable = new EditorManager(vscode.Uri.joinPath(this.uri, 'editor_table')); + this.scriptUri = vscode.Uri.joinPath(this.uri, 'script'); } async start() { @@ -382,6 +384,7 @@ class Env { return; } this.projectUri = projectUri; + this.globalScriptUri = vscode.Uri.joinPath(this.projectUri, 'global_script'); this.project = new Project(projectUri); await this.project.start(); if (!this.project.entryMap) { diff --git a/src/extension.ts b/src/extension.ts index 540325d..dd2089e 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -21,6 +21,7 @@ import * as editorTable from './editorTable'; import * as plugin from './plugin'; import * as y3 from 'y3-helper'; import { config } from './config'; +import * as watcher from './watcher'; class Helper { private context: vscode.ExtensionContext; @@ -301,6 +302,7 @@ class Helper { console.init(); editorTable.init(); plugin.init(); + watcher.init(); }, 100); } } diff --git a/src/mainMenu/pages/features.ts b/src/mainMenu/pages/features.ts index eaeabdb..d7b8efb 100644 --- a/src/mainMenu/pages/features.ts +++ b/src/mainMenu/pages/features.ts @@ -4,6 +4,7 @@ import * as vscode from 'vscode'; import * as y3 from 'y3-helper'; import { config } from "../../config"; import { TreeViewManager } from "../../console/treeView"; +import { isGlobalScriptEnabled } from "./mapManager"; function 多开模式() { let node = new TreeNode('多开模式', { @@ -121,7 +122,8 @@ export class 功能 extends TreeNode { } }, show: async () => { - return !await y3.fs.isExists(vscode.Uri.joinPath(env.y3Uri!, '更新日志.md')); + return !await y3.fs.isExists(vscode.Uri.joinPath(env.y3Uri!, '更新日志.md')) + && !await isGlobalScriptEnabled(); } }), new TreeNode('启动游戏', { diff --git a/src/mainMenu/pages/mapManager.ts b/src/mainMenu/pages/mapManager.ts index 111cb12..a4ac928 100644 --- a/src/mainMenu/pages/mapManager.ts +++ b/src/mainMenu/pages/mapManager.ts @@ -1,16 +1,122 @@ import { TreeNode, ViewInVSCode } from "../treeNode"; import * as vscode from 'vscode'; import { env } from "../../env"; +import * as y3 from 'y3-helper'; export async function isGlobalScriptEnabled() { if (!env.globalScriptUri) { return false; } let rcUri = vscode.Uri.joinPath(env.globalScriptUri, '.luarc.json'); + let y3Uri = vscode.Uri.joinPath(env.globalScriptUri, 'y3'); + return (await y3.fs.stat(rcUri))?.type === vscode.FileType.File + && (await y3.fs.stat(y3Uri))?.type === vscode.FileType.Directory; } -export function enableGlobalScript() { - +export async function enableGlobalScript() { + if (!env.globalScriptUri) { + y3.log.error("没有找到全局脚本目录"); + return false; + } + let entryMap = env.project?.entryMap; + if (!entryMap) { + y3.log.error("没有找到入口地图"); + return false; + } + let y3Uri = vscode.Uri.joinPath(entryMap.uri, 'script/y3'); + if (!await y3.fs.isExists(y3Uri)) { + y3.log.error("请先初始化地图"); + return false; + } + // 把Y3库复制到全局脚本目录 + let globalY3Uri = vscode.Uri.joinPath(env.globalScriptUri, 'y3'); + if (!await y3.fs.isExists(globalY3Uri)) { + await y3.fs.copy(y3Uri, globalY3Uri, { + recursive: true, + }); + } + // 遍历所有地图,修改luarc文件 + for (const map of env.project!.maps) { + let rcUri = vscode.Uri.joinPath(map.uri, '.luarc.json'); + await rcAddGlobalPath(rcUri); + } + // 生成全局的luarc文件 + let globalRcUri = vscode.Uri.joinPath(env.globalScriptUri, '.luarc.json'); + if (!await y3.fs.isExists(globalRcUri)) { + await y3.fs.copy(vscode.Uri.joinPath(globalY3Uri, '演示/项目配置/.luarc.json'), globalRcUri); + } + // 修改全局里的luarc文件 + await rcRemoveGlobalPath(globalRcUri); + // 遍历所有地图,删除他们的y3文件夹 + for (const map of env.project!.maps) { + let y3Uri = vscode.Uri.joinPath(map.uri, 'script/y3'); + await y3.fs.removeFile(y3Uri, { + recursive: true, + useTrash: true, + }); + } + return true; +} + +function mergeArray(a: any, b: any[]): any[] { + if (!Array.isArray(a)) { + return b; + } + let set = new Set(a); + for (let value of b) { + set.add(value); + } + return Array.from(set); +} + +function subtractArray(a: any, b: any[]): any[] { + if (!Array.isArray(a)) { + return []; + } + let set = new Set(b); + return a.filter(value => !set.has(value)); +} + +async function rcAddGlobalPath(rcUri: vscode.Uri) { + let file = await y3.fs.readFile(rcUri); + if (!file) { + return; + } + let tree = new y3.json.Json(file.string); + try { + tree.set('runtime.path', mergeArray(tree.get('runtime.path'), [ + "../../../global_script/?.lua", + "../../../global_script/?/init.lua" + ])); + tree.set('workspace.library', mergeArray(tree.get('workspace.library'), [ + "../../../global_script" + ])); + await y3.fs.writeFile(rcUri, tree.text); + } catch (error) { + y3.log.error(`修改${rcUri.fsPath}时发生错误: ${error}`); + return; + } +} + +async function rcRemoveGlobalPath(rcUri: vscode.Uri) { + let file = await y3.fs.readFile(rcUri); + if (!file) { + return; + } + let tree = new y3.json.Json(file.string); + try { + tree.set('runtime.path', subtractArray(tree.get('runtime.path'), [ + "../../../global_script/?.lua", + "../../../global_script/?/init.lua" + ])); + tree.set('workspace.library', subtractArray(tree.get('workspace.library'), [ + "../../../global_script" + ])); + await y3.fs.writeFile(rcUri, tree.text); + } catch (error) { + y3.log.error(`修改${rcUri.fsPath}时发生错误: ${error}`); + return; + } } export class 地图管理 extends TreeNode { @@ -37,18 +143,26 @@ export class 地图管理 extends TreeNode { node.childs.push(new TreeNode('------------------', { tooltip: '我只是一个分割线', })); - // node.childs.push(new TreeNode('启用全局脚本', { - // command: { - // command: 'y3-helper.enableGlobalScript', - // title: '启用全局脚本', - // }, - // })); if (env.scriptUri) { let openScriptFolder = new ViewInVSCode(env.scriptUri, '打开脚本目录'); openScriptFolder.description = currentMap?.name; openScriptFolder.tooltip = '会重启VSCode窗口'; node.childs.push(openScriptFolder); } + node.childs.push(new TreeNode('启用全局脚本', { + iconPath: new vscode.ThemeIcon('remote-explorer'), + tooltip: '所有地图都可以使用全局脚本。地图内的脚本优先级高于全局脚本。', + command: { + command: 'y3-helper.enableGlobalScript', + title: '启用全局脚本', + }, + show: async () => { + return !await isGlobalScriptEnabled(); + } + })); + node.childs.push(new TreeNode('一并打开全局脚本', { + + })); }, }); @@ -65,3 +179,33 @@ vscode.commands.registerCommand('y3-helper.changeMap', async (name: string) => { } env.updateCurrentMap(map); }); + +let lock = false; +vscode.commands.registerCommand('y3-helper.enableGlobalScript', async () => { + if (lock) { + return; + } + lock = true; + let result = await vscode.window.showWarningMessage('这会移动y3文件夹到全局脚本目录并重启所有扩展,是否继续?', '继续'); + if (result !== '继续') { + lock = false; + return; + } + await vscode.commands.executeCommand('git.close'); + await vscode.window.withProgress({ + location: vscode.ProgressLocation.Notification, + title: "正在启用全局脚本", + cancellable: false, + }, async (progress) => { + progress.report({ message: "正在启用全局脚本" }); + let suc = await enableGlobalScript(); + if (suc) { + vscode.window.showInformationMessage("已启用全局脚本"); + vscode.commands.executeCommand('workbench.action.restartExtensionHost'); + } else { + vscode.window.showErrorMessage("启用全局脚本失败"); + y3.log.show(); + } + }); + lock = false; +}); diff --git a/src/watcher.ts b/src/watcher.ts new file mode 100644 index 0000000..dc59083 --- /dev/null +++ b/src/watcher.ts @@ -0,0 +1,22 @@ +import * as y3 from 'y3-helper'; + +function syncY3() { + setInterval(async () => { + if (!y3.env.globalScriptUri || !y3.env.scriptUri) { + return; + } + let globalY3 = await y3.fs.readFile(y3.env.globalScriptUri, 'y3/init.lua'); + if (!globalY3) { + return; + } + let myY3 = await y3.fs.readFile(y3.env.scriptUri, 'y3/init.lua'); + + if (!myY3 || globalY3.string !== myY3.string) { + await y3.fs.writeFile(y3.env.scriptUri, 'y3/init.lua', globalY3.string); + } + }, 1000); +} + +export function init() { + syncY3(); +}