diff --git a/noname/game/index.js b/noname/game/index.js index 17d7adacd..ee1a64f7f 100644 --- a/noname/game/index.js +++ b/noname/game/index.js @@ -1461,7 +1461,10 @@ export class Game { * @returns { string[] } 语音地址列表 */ parseSkillText(skill, player, skillInfo) { - return game.parseSkillTextMap(skill, player, skillInfo).map(data => data.text).filter(Boolean); + return game + .parseSkillTextMap(skill, player, skillInfo) + .map(data => data.text) + .filter(Boolean); } /** * 根据skill中的audio,audioname,audioname2和player来获取技能台词列表及其对应的源文件名 @@ -1489,19 +1492,22 @@ export class Game { const getName = filter => { const name = (player.tempname || []).find(i => filter(i)); if (name) return name; - return [player.name, player.name1, player.name2].reduce((result, name) => { - if (result) return result; - if (!name) return result; - if (filter(name)) return name; - return get.character(name).tempname.find(i => filter(i)) || result; - }, void 0); + return [player.name, player.name1, player.name2].reduce( + (result, name) => { + if (result) return result; + if (!name) return result; + if (filter(name)) return name; + return get.character(name).tempname.find(i => filter(i)) || result; + }, + void 0 + ); }; const getTextMap = (path, name, ext, isDefault) => ({ name, file: `${path}${name}${ext}`, text: lib.translate[`#${name}`], - isDefault + isDefault, }); const getAudioList = (skill, options, skillInfo) => { @@ -1518,7 +1524,7 @@ export class Game { if (info.audioname2) audioInfo = info.audioname2[getName(i => info.audioname2[i])] || audioInfo; return parseAudio(skill, options, audioInfo); - } + }; const parseAudio = (skill, options, audioInfo) => { const audioname = options.audioname.slice(); @@ -1533,8 +1539,8 @@ export class Game { } const map = {}; - audioInfo.forEach((i) => { - parseAudio(skill, options, i).forEach(data => map[data.name] = data); + audioInfo.forEach(i => { + parseAudio(skill, options, i).forEach(data => (map[data.name] = data)); }); return Object.values(map); } @@ -1551,9 +1557,7 @@ export class Game { let [, path = "skill", audioNum, ext = "mp3"] = list; let _audioname = getName(i => audioname.includes(i)); _audioname = _audioname ? `_${_audioname}` : ""; - if (audioNum === "true") return [getTextMap(`${path}/`, `${skill}${_audioname}`, `.${ext}`, isDefault)]; - const audioList = []; audioNum = parseInt(audioNum); for (let i = 1; i <= audioNum; i++) { @@ -1584,16 +1588,15 @@ export class Game { if (typeof player !== "string" && player.skin && player.skin.name) { const skinName = player.skin.name; if (skinName !== name && lib.characterSubstitute[name]) { - const skin = lib.characterSubstitute[name].find((i) => i[0] === skinName); + const skin = lib.characterSubstitute[name].find(i => i[0] === skinName); if (skin) { - const newCharacter = get.convertedCharacter(['', '', 0, [], skin[1]]); + const newCharacter = get.convertedCharacter(["", "", 0, [], skin[1]]); name = skinName; audioInfo = newCharacter.dieAudios; } } } - const defaultInfo = true; const check = (name, history) => { @@ -1608,7 +1611,7 @@ export class Game { name, file: `${path}${name}${ext}`, text: lib.translate[`#${name}:die`], - isDefault + isDefault, }); const getAudioList = (name, options, audioInfo) => { @@ -1627,7 +1630,7 @@ export class Game { history.unshift(name); return parseAudio(name, options, audioInfo); - } + }; const parseAudio = (name, options, audioInfo) => { const history = options.history.slice(); @@ -1641,8 +1644,8 @@ export class Game { // } const map = {}; - audioInfo.forEach((i) => { - parseAudio(name, options, i).forEach(data => map[data.name] = data); + audioInfo.forEach(i => { + parseAudio(name, options, i).forEach(data => (map[data.name] = data)); }); return Object.values(map); } @@ -1668,14 +1671,15 @@ export class Game { return audioList; } - let path = "", ext = ""; + let path = "", + ext = ""; if (!/^db:|^ext:|\//.test(audioInfo)) path = "die/"; if (!/\.\w+$/.test(audioInfo)) ext = ".mp3"; if (path && ext) return parseAudio(audioInfo, Object.assign(options, { isDefault: true }), defaultInfo); //@TODO console.warn(`${name}中的地址写法(${audioInfo})暂时没有完全支持台词系统。`); return [getTextMap(path, audioInfo, ext, isDefault)]; - } + }; return getAudioList(name, { history: [], isDefault: false }, audioInfo); } @@ -1695,8 +1699,8 @@ export class Game { if (!lib.config.background_speak) return; if (info.direct && !directaudio) return; if (lib.skill.global.includes(skill) && !info.forceaudio) return; - - let audio, list = game.parseSkillTextMap(skill, player, skillInfo).randomSort(); + let audio, + list = game.parseSkillTextMap(skill, player, skillInfo).randomSort(); return (function play() { if (!list.length) return; audio = list.shift(); @@ -1716,7 +1720,9 @@ export class Game { else if (player.skin && player.skin.name) playerName = player.skin.name; else playerName = player.name; - let audio, isDefault, list = game.parseDieTextMap(player).randomSort(); + let audio, + isDefault, + list = game.parseDieTextMap(player).randomSort(); const check = () => { if (list.length) return true; if (!audio) return false; @@ -1725,7 +1731,7 @@ export class Game { playerName = playerName.slice(playerName.indexOf("_") + 1); list = game.parseDieTextMap(playerName).randomSort(); return check(); - } + }; return (function play() { if (!check()) return; audio = list.shift(); @@ -3416,8 +3422,7 @@ export class Game { }; // player.removeGaintag.apply(player, content); checkMatch(content[1], player.getCards("h")); - } - else player.removeGaintag(content); + } else player.removeGaintag(content); } else { console.log(player); } @@ -5906,19 +5911,19 @@ export class Game { // 数组形式 if ("contents" in event && Array.isArray(event.contents)) { /* - event.contents[step](event, trigger, player, _storeEvent).then((evt) => { - if (evt) event._storeEvent = evt; - if (game.executingAsyncEventMap.has(event.toEvent())) { - game.executingAsyncEventMap.set(_status.event.toEvent(), game.executingAsyncEventMap.get(_status.event.toEvent()).then(() => { - if (event.step >= event.contents.length - 1) event.finish(); - resolve(); - })); - } else { - if (event.step >= event.contents.length - 1) event.finish(); - resolve(); - } - }); - */ + event.contents[step](event, trigger, player, _storeEvent).then((evt) => { + if (evt) event._storeEvent = evt; + if (game.executingAsyncEventMap.has(event.toEvent())) { + game.executingAsyncEventMap.set(_status.event.toEvent(), game.executingAsyncEventMap.get(_status.event.toEvent()).then(() => { + if (event.step >= event.contents.length - 1) event.finish(); + resolve(); + })); + } else { + if (event.step >= event.contents.length - 1) event.finish(); + resolve(); + } + }); + */ // 解决不了问题...就把问题统一 const run = async event => { if (typeof event.step !== "number") event.step = 0; @@ -7082,7 +7087,7 @@ export class Game { for (let i = 0; i < event.config.size; i++) { ui.window.appendChild(event.nodes[i]); } - "step 1"; + ("step 1"); let rand1 = event.config.first; if (rand1 == "rand") { rand1 = Math.random() < 0.5; @@ -7119,7 +7124,7 @@ export class Game { } game.delay(); lib.init.onfree(); - "step 2"; + ("step 2"); if (event.checkredo()) return; if (event._skiprest) return; if (event.side < 2) { @@ -7135,7 +7140,7 @@ export class Game { event.aiMove(); game.delay(); } - "step 3"; + ("step 3"); if (typeof event.fast == "number" && get.time() - event.fast <= 1000) { event.fast = true; } else { @@ -7170,7 +7175,7 @@ export class Game { game.delay(); } } - "step 4"; + ("step 4"); if (event.checkredo()) return; if (event.skipnode) event.skipnode.delete(); if (event.replacenode) event.replacenode.delete(); @@ -7189,7 +7194,7 @@ export class Game { } } game.delay(); - "step 5"; + ("step 5"); event.prompt("选择" + get.cnNumber(event.config.num) + "名出场武将"); event.enemylist = []; for (let i = 0; i < event.avatars.length; i++) { @@ -7219,7 +7224,7 @@ export class Game { event.nodes[i].hide(); } game.pause(); - "step 6"; + ("step 6"); event.promptbar.delete(); if (ui.cardPileButton) ui.cardPileButton.style.display = ""; lib.onresize.remove(event.resize); @@ -7926,7 +7931,7 @@ export class Game { game.reload2(); resolve(result); }; - } + } : (resolve, reject) => { lib.status.reload++; const idbRequest = lib.db.transaction([storeName], "readwrite").objectStore(storeName).openCursor(), @@ -7956,7 +7961,7 @@ export class Game { game.reload2(); resolve(object); }; - } + } ); } /** @@ -8010,7 +8015,7 @@ export class Game { game.reload2(); resolve(event); }; - }) + }) : game.getDB(storeName).then(object => { const keys = Object.keys(object); lib.status.reload += keys.length; @@ -8031,7 +8036,7 @@ export class Game { }) ) ); - }); + }); } /** * @param { string } key diff --git a/noname/get/index.js b/noname/get/index.js index 5d08380ea..5e223e177 100644 --- a/noname/get/index.js +++ b/noname/get/index.js @@ -216,7 +216,7 @@ export class Get { //装备栏 END /** * @param {string} chinese - * @param {boolean|undefined} withTone + * @param {boolean|undefined} withTone * @returns { any[] } */ pinyin(chinese, withTone) { @@ -224,10 +224,9 @@ export class Get { const pinyins = lib.pinyins; if (pinyins && pinyins[chinese] && Array.isArray(pinyins[chinese])) { result = pinyins[chinese].slice(0); - } - else { + } else { //@ts-ignore - result = pinyinPro.pinyin(chinese, {type: "array"}); + result = pinyinPro.pinyin(chinese, { type: "array" }); } //@ts-ignore if (withTone === false) result = pinyinPro.convert(result, { format: "toneNone" }); @@ -295,7 +294,7 @@ export class Get { */ yunjiao(str) { //@ts-ignore - str = pinyinPro.convert(str, { format: "toneNone" }) + str = pinyinPro.convert(str, { format: "toneNone" }); if (lib.pinyins._metadata.zhengtirendu.includes(str)) { str = "-" + str[str.length - 1]; } else { @@ -4601,7 +4600,8 @@ export class Get { ) temp2 = cache.delegate(temp2.effect).target(card, player, target, result2, isLink); else temp2 = undefined; - } else if (typeof temp2.effect == "function") { //考虑废弃 + } else if (typeof temp2.effect == "function") { + //考虑废弃 console.log("此写法使用频率极低且影响代码可读性,不建议使用"); if ( !player.hasSkillTag("ignoreSkill", true, { @@ -4832,7 +4832,7 @@ export class Get { * * @async * @param {Blob} blob - 需要转换的内容 - * @returns {Promise} 对应Blob内容的 + * @returns {Promise} 对应Blob内容的 * * @example * let text = "Hello, World!"; @@ -4840,7 +4840,7 @@ export class Get { * * let blob = new Blob([text], { type: "text/plain" }); * let url = await get.dataUrlAsync(blob); - * console.assert("data:text/plain;base64,SGVsbG8sIFdvcmxkIQ=="); + * console.assert(url.href === "data:text/plain;base64,SGVsbG8sIFdvcmxkIQ=="); */ dataUrlAsync(blob) { return new Promise((resolve, reject) => { @@ -4848,11 +4848,13 @@ export class Get { fileReader.onload = resolve; fileReader.onerror = reject; fileReader.readAsDataURL(blob); - }).then(event => event.target.result); + }).then(event => new URL(event.target.result)); } /** - * 通过`fetch`读取data URL的内容,转换成Blob后返回生成的blob URL + * 通过`Get#blobFromUrl`读取data URL的内容,转换成Blob后返回生成的blob URL + * + * > 实际上所有的URL都能通过此方法读取 * * 该方法具有缓存,同一data URL仅会返回同一blob URL * @@ -4866,16 +4868,30 @@ export class Get { * @param {string | URL} dataUrl - 需要转换的data URL * @returns {Promise} */ - async objectURLAsync(dataUrl) { + async objectUrlAsync(dataUrl) { let dataString = dataUrl instanceof URL ? dataUrl.href : dataUrl; const objectURLMap = lib.objectURL; if (objectURLMap.has(dataString)) return new URL(objectURLMap.get(dataString)); - let blob = await (await fetch(dataUrl)).blob(); + let blob = await this.blobFromUrl(dataUrl); const objectURL = URL.createObjectURL(blob); objectURLMap.set(dataString, objectURL); return new URL(objectURL); } + + /** + * 读取给定的URL,将其中的内容转换成Blob + * + * 在File协议下通过无名杀自带的文件处理函数读取内容,其他协议通过`fetch`读取内容 + * + * @async + * @param {string | URL} url - 需要读取的URL + * @returns {Promise} + */ + blobFromUrl(url) { + let link = url instanceof URL ? url : new URL(url); + return link.protocol == "file:" ? game.promises.readFile(get.relativePath(link)).then(buffer => new Blob([buffer])) : fetch(link).then(response => response.blob()); + } } export let get = new Get(); diff --git a/noname/library/init/index.js b/noname/library/init/index.js index be1233119..704ba8831 100644 --- a/noname/library/init/index.js +++ b/noname/library/init/index.js @@ -838,18 +838,24 @@ export class LibInit { } /** - * @async * @param {string | URL} link - 需要解析的路径 * @param {((item: string) => string) | null} [defaultHandle] - 在给定路径不符合可用情况(或基于无名杀相关默认情况)时,处理路径的函数,返回的路径应是相对于根目录的相对路径,默认为`null`,当且仅当无法解析成`URL`时会调用该回调 - * @param {boolean} [forceLoadAsDataUrl] - 是否将资源加载为[Data URL](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Basics_of_HTTP/Data_URLs),默认为`false` + * @param {((item: URL) => unknown) | null} [loadAsDataUrlCallback] - 若存在值,则将资源加载为[Data URL](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Basics_of_HTTP/Data_URLs),然后传入进回调函数 * @param {boolean} [dbNow] - 此刻是否在解析数据库中的内容,请勿直接使用 - * @returns {Promise} + * @returns {URL} */ - async parseResourceAddress(link, defaultHandle = null, forceLoadAsDataUrl = false, dbNow = false) { + parseResourceAddress(link, defaultHandle = null, loadAsDataUrlCallback = null, dbNow = false) { + // 适当的摆了,中文错误应该没人会反对 + if (!link) throw new Error(dbNow ? "传入的数据库链接中不存在内容" : "请传入需要解析的链接"); + let linkString = link instanceof URL ? link.href : link; // 如果传入值为Data URL,经过分析可知无需处理,故直接返回成品URL - if (linkString.startsWith("data:")) return new URL(linkString); + if (linkString.startsWith("data:")) { + let result = new URL(linkString); + if (loadAsDataUrlCallback) loadAsDataUrlCallback(result); + return result; + } /** * @type {URL} @@ -862,37 +868,24 @@ export class LibInit { resultUrl = new URL(linkString); } else if (dbNow) { let content = new Blob([linkString], { type: "text/plain" }); - resultUrl = new URL(await get.dataUrlAsync(content)); + get.dataUrlAsync(content).then(loadAsDataUrlCallback); + // @ts-expect-error 此处的返回值无任何用处 + return; } else { let resultLink = defaultHandle == null ? linkString : defaultHandle(linkString); resultUrl = new URL(resultLink, rootURL); } - if (forceLoadAsDataUrl && !resultUrl.href.startsWith("data:")) { - if (linkString.startsWith("db:")) { - /** - * @type {string} - */ - let storeResult = await game.getDB("image", linkString.slice(3)); - + if (loadAsDataUrlCallback != null) { + if (resultUrl.protocol == "db:") { // 我思索了一下,如果这玩意能造成无限递归 // 那么我只能说,你赢了 - return this.parseResourceAddress(storeResult, defaultHandle, forceLoadAsDataUrl, true); - } - /** - * @type {Blob} - */ - let blob; - - if (linkString.startsWith("file:")) { - let buffer = await game.promises.readFile(get.relativePath(resultUrl)); - blob = new Blob([buffer]); + game.getDB("image", linkString.slice(3)).then(storeResult => this.parseResourceAddress(storeResult, defaultHandle, loadAsDataUrlCallback, true)); } else { - let response = await fetch(resultUrl.href); - blob = await response.blob(); + get.blobFromUrl(resultUrl) + .then(blob => get.dataUrlAsync(blob)) + .then(loadAsDataUrlCallback); } - - resultUrl.href = await get.dataUrlAsync(blob); } return resultUrl; diff --git a/noname/library/init/promises.js b/noname/library/init/promises.js index 0b50e1d3e..4597a0b8b 100644 --- a/noname/library/init/promises.js +++ b/noname/library/init/promises.js @@ -72,6 +72,23 @@ export class LibInitPromises { * @returns {Promise} */ parseResourceAddress(link, defaultHandle = null, forceLoadAsDataUrl = false) { - return lib.init.parseResourceAddress(link, defaultHandle, forceLoadAsDataUrl); + if (!forceLoadAsDataUrl) return Promise.resolve(lib.init.parseResourceAddress(link, defaultHandle)); + let { promise, resolve } = Promise.withResolvers(); + + lib.init.parseResourceAddress(link, defaultHandle, result => resolve(result)); + return promise; + } + + /** + * @async + * @param {string | URL} link - 需要解析的路径 + * @param {((item: string) => string) | null} [defaultHandle] - 在给定路径不符合可用情况(或基于无名杀相关默认情况)时,处理路径的函数,返回的路径应是相对于根目录的相对路径,默认为`null`,当且仅当无法解析成`URL`时会调用该回调 + * @returns {Promise<[origin: URL, data: URL]>} + */ + async parseResourceAddressExt(link, defaultHandle = null) { + let { promise, resolve } = Promise.withResolvers(); + + let origin = lib.init.parseResourceAddress(link, defaultHandle, result => resolve(result)); + return [origin, await promise]; } }