From 5a39ed5260c5d6ea951211e8e0b67d4126fb8720 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=80=E8=90=8C=E5=B0=8F=E6=B1=90?= Date: Fri, 22 Mar 2024 18:27:35 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AF=BC=E5=85=A5=E4=B8=8B=E8=BD=BD=E7=9A=84?= =?UTF-8?q?=E8=B5=84=E6=BA=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/extension.ts | 7 +- src/launchGame.ts | 1 + src/preset/ui.ts | 198 +++++++++++++++++++++++++++++++++------------- 3 files changed, 151 insertions(+), 55 deletions(-) diff --git a/src/extension.ts b/src/extension.ts index 6e2fe00..bee8145 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -327,7 +327,12 @@ class Helper { vscode.window.showErrorMessage("未找到地图路径!"); return false; }; - new preset.UI(this.env).make(); + await vscode.window.withProgress({ + location: vscode.ProgressLocation.Notification, + title: '正在下载预设UI...', + }, async (progress, token) => { + await new preset.UI(this.env).make(); + }); }); } diff --git a/src/launchGame.ts b/src/launchGame.ts index 461d16d..e03c0e2 100644 --- a/src/launchGame.ts +++ b/src/launchGame.ts @@ -42,6 +42,7 @@ export class GameLauncher { "--start=Python", "--python-args=" + args.join(","), "--plugin-config=Plugins-PyQt", + "--python-builtin-path=E:/up1-uat/src/Server/server/engine", //"--python-debug=1", ], vscode.Uri.joinPath(editorExeUri, "..") diff --git a/src/preset/ui.ts b/src/preset/ui.ts index 116d881..baad5d9 100644 --- a/src/preset/ui.ts +++ b/src/preset/ui.ts @@ -4,31 +4,30 @@ import JSZip from 'jszip'; import vscode from 'vscode'; import xml from 'fast-xml-parser'; import * as uuid from 'uuid'; +import * as util from 'util'; + +interface TextureInfo { + oldName: number; + newName: number; + oldGuid: string; + newGuid: string; + xml: { [key: string]: any }; + icon?: string; + texture?: Buffer; + noUse?: boolean; +} export class UI { private env: Env; private zip?: JSZip; - private uiFiles?: { [key: string]: string }; - private tableFiles?: { [key: string]: string }; private resourceXml?: { [key: string]: any }; - private namePatch?: { [key: number]: number }; private resourceXmlUri: vscode.Uri; + private textureInfos: TextureInfo[]; constructor(env: Env) { this.env = env; this.resourceXmlUri = vscode.Uri.joinPath(this.env.projectUri!, 'custom/CustomImportRepo.local/resource.repository'); - } - - private async pickZipFiles(zip: JSZip, basePath: string): Promise<{ [key: string]: string }> { - let files: { [key: string]: string } = {}; - - for (const file of zip.filter((path) => path.startsWith(basePath))) { - let name = file.name.slice(basePath.length); - let content = await file.async('string'); - files[name] = content; - } - - return files; + this.textureInfos = []; } public async make() { @@ -42,8 +41,6 @@ export class UI { this.zip = await new JSZip().loadAsync(downloadBuffer); - this.uiFiles = await this.pickZipFiles(this.zip, 'maps/EntryMap/ui/'); - this.tableFiles = await this.pickZipFiles(this.zip, 'editor_table/editoricon/'); let xmlBuffer = await this.zip.file("custom/CustomImportRepo.local/resource.repository")?.async('nodebuffer'); if (!xmlBuffer) { tools.log.error("下载的文件中没有resource.repository!"); @@ -53,17 +50,44 @@ export class UI { ignoreAttributes: false, }).parse(xmlBuffer); - try { - this.avoidConfict(); - } catch {} + if (!this.resourceXml) { + tools.log.error("resource.repository解析失败!"); + return; + } + await this.makeTextureInfos(); + await this.avoidConfict(); await this.mergeResourceXml(); + await this.importResource(); + } + + private async makeTextureInfos() { + let items = this.getXmlItem(this.resourceXml!, 'Repository.Items.Item'); + items = typeof items === 'object' ? items : []; + for (let item of items) { + let name: number = item.Name; + let guid: string = item.GUID; + this.textureInfos.push({ + oldName: name, + newName: name, + oldGuid: guid, + newGuid: guid, + xml: item, + icon: await this.zip!.file(`editor_table/editoricon/${name.toString()}.json`)?.async('string'), + texture: await this.zip!.file(`custom/CustomImportRepo.local/Texture/${guid.slice(0, 2)}/{${guid}}/texture`)?.async('nodebuffer'), + }); + } } private async avoidConfict() { // 读取项目中已经存在的resource.repository - let xmlContent = Buffer.from(await vscode.workspace.fs.readFile(this.resourceXmlUri)); - let localXml = new xml.XMLParser().parse(xmlContent); + let localXml; + try { + let xmlContent = Buffer.from(await vscode.workspace.fs.readFile(this.resourceXmlUri)); + localXml = new xml.XMLParser().parse(xmlContent); + } catch { + return; + } let itemsPart = localXml?.Repository?.Items; let items = typeof itemsPart === 'object' ? itemsPart.Item : undefined; @@ -77,24 +101,31 @@ export class UI { usedNames.add(name); } + let usedGuids = new Set(); + for (let item of items) { + let guid = item.GUID; + usedGuids.add(guid); + } + // 将resourceXml中冲突的name改为未使用的name - this.namePatch = {}; - let newItems = this.resourceXml?.Repository?.Items; - if (newItems) { - for (let item of newItems.Item) { - let name = item.Name; - if (typeof name !== 'number') { - continue; - } - if (usedNames.has(name)) { - let newName = name; - while (usedNames.has(newName)) { - newName++; - } - this.namePatch[name] = newName; - usedNames.add(newName); + for (let texture of this.textureInfos) { + if (typeof texture.oldName !== 'number') { + continue; + } + if (texture.icon === undefined) { + if (usedNames.has(texture.oldName)) { + texture.noUse = true; } + continue; + } + while (usedNames.has(texture.newName)) { + texture.newName++; } + usedNames.add(texture.newName); + while (usedGuids.has(texture.newGuid)) { + texture.newGuid = uuid.v4(); + } + usedGuids.add(texture.newGuid); } } @@ -129,27 +160,26 @@ export class UI { } private async mergeResourceXml() { - if (!this.resourceXml) { - return; - } // 读取项目中已经存在的resource.repository - let xmlContent = Buffer.from(await vscode.workspace.fs.readFile(this.resourceXmlUri)); - let localXml = new xml.XMLParser({ - ignoreAttributes: false, - }).parse(xmlContent) ?? {}; + let localXml; + try { + let xmlContent = Buffer.from(await vscode.workspace.fs.readFile(this.resourceXmlUri)); + localXml = new xml.XMLParser({ + ignoreAttributes: false, + }).parse(xmlContent) ?? {}; + } catch { + localXml = {}; + } let items = this.getXmlItem(localXml, 'Repository.Items.Item'); items = typeof items === 'object' ? items : []; this.setXmlItem(localXml, 'Repository.Items.Item', items); - // 将resourceXml中的内容合并到项目中,如果有冲突则修改name - let newItems = this.getXmlItem(this.resourceXml, 'Repository.Items.Item') ?? []; - for (let item of newItems) { - let name = item.Name; - item.GUID = uuid.v4(); - if (this.namePatch && this.namePatch[name]) { - item.Name = this.namePatch[name]; - item.Annotation.SourcePath = item.Annotation.SourcePath.replace(name.toString(), this.namePatch[name].toString()); - } - items.push(item); + // 将resourceXml中的内容合并到项目中 + let textureInfos = this.textureInfos.filter((texture) => !texture.noUse); + for (let texture of textureInfos) { + let xml = { ...texture.xml }; + xml.Name = texture.newName; + xml.GUID = texture.newGuid; + items.push(xml); } let newXmlContent = new xml.XMLBuilder({ format: true, @@ -159,4 +189,64 @@ export class UI { await vscode.workspace.fs.writeFile(this.resourceXmlUri, Buffer.from(newXmlContent)); } + + private async importResource() { + let total = 0; + let resolved = 0; + + async function pushTask(thenable: Thenable) { + total++; + thenable.then(() => { + resolved++; + }); + } + + // 导入资源文件 + let textureInfos = this.textureInfos; + for (let textureInfo of textureInfos) { + let icon = textureInfo.icon; + if (icon !== undefined) { + let iconUri = vscode.Uri.joinPath(this.env.projectUri!, 'editor_table/editoricon', textureInfo.newName.toString() + '.json'); + pushTask(vscode.workspace.fs.writeFile(iconUri, Buffer.from(icon))); + } + let texture = textureInfo.texture; + if (texture !== undefined) { + let textureUri = vscode.Uri.joinPath(this.env.projectUri!, 'custom/CustomImportRepo.local/Texture', textureInfo.newGuid.slice(0, 2), `{${textureInfo.newGuid}}`, 'texture'); + pushTask(vscode.workspace.fs.writeFile(textureUri, texture)); + } + } + + // 导入UI定义 + let basePath = 'maps/EntryMap/ui/'; + for (let file of this.zip!.filter(path => path.startsWith(basePath))) { + if (file.dir) { + continue; + } + let fileContent = await file.async('string'); + if (fileContent === undefined) { + continue; + } + let uri = vscode.Uri.joinPath(this.env.mapUri!, 'ui', file.name.slice(basePath.length)); + pushTask(vscode.workspace.fs.writeFile(uri, Buffer.from(fileContent))); + } + + await vscode.window.withProgress({ + location: vscode.ProgressLocation.Notification, + title: "正在导入资源文件...", + cancellable: false, + }, async (progress) => { + progress.report({ increment: 0, message: `(${resolved}/${total})` }); + let last = 0; + while (resolved < total) { + await util.promisify(setTimeout)(100); + let delta = resolved - last; + if (delta === 0) { + continue; + } + last = resolved; + progress.report({ increment: delta / total * 100, message: `(${resolved}/${total})` }); + } + progress.report({ increment: 100, message: "导入资源完成!" }); + }); + } }