Skip to content

Commit

Permalink
导入下载的资源
Browse files Browse the repository at this point in the history
  • Loading branch information
sumneko committed Mar 22, 2024
1 parent 97754d2 commit 5a39ed5
Show file tree
Hide file tree
Showing 3 changed files with 151 additions and 55 deletions.
7 changes: 6 additions & 1 deletion src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();
});
});
}

Expand Down
1 change: 1 addition & 0 deletions src/launchGame.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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, "..")
Expand Down
198 changes: 144 additions & 54 deletions src/preset/ui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand All @@ -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!");
Expand All @@ -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;

Expand All @@ -77,24 +101,31 @@ export class UI {
usedNames.add(name);
}

let usedGuids = new Set<string>();
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);
}
}

Expand Down Expand Up @@ -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,
Expand All @@ -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<any>) {
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: "导入资源完成!" });
});
}
}

0 comments on commit 5a39ed5

Please sign in to comment.