Merge pull request #1347 from Rintim/Dev-Enhancement-UniteResource
重新制定`lib.init.parseResourceAddress`的API
This commit is contained in:
commit
b6dbe2a135
|
@ -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
|
||||
|
|
|
@ -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<string>} 对应Blob内容的
|
||||
* @returns {Promise<URL>} 对应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<URL>}
|
||||
*/
|
||||
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<Blob>}
|
||||
*/
|
||||
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();
|
||||
|
|
|
@ -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<URL>}
|
||||
* @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;
|
||||
|
|
|
@ -72,6 +72,23 @@ export class LibInitPromises {
|
|||
* @returns {Promise<URL>}
|
||||
*/
|
||||
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];
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue