[bugfix] fix mod loading by removing side effects (#860)

* added more loading when loading mods
This commit is contained in:
silentrald
2025-04-24 21:09:53 +08:00
committed by GitHub
parent 2714a125f2
commit cc4061fd38
3 changed files with 59 additions and 38 deletions
@@ -70,17 +70,17 @@ export class BeatModsApiService {
});
}
public getModByHash(hash: string): Promise<BbmModVersion|undefined> {
public async getModByHash(hash: string): Promise<BbmModVersion> {
if (this.modsHashCache.has(hash)) {
return Promise.resolve(this.modsHashCache.get(hash));
}
return this.requestService.getJSON<{ modVersions: BbmModVersion[] }>(`${this.MODS_REPO_API_URL}/hashlookup?hash=${hash}`).then(({ data }) => {
return this.requestService.getJSON<{ modVersions: BbmModVersion[] }>(
`${this.MODS_REPO_API_URL}/hashlookup?hash=${hash}`,
{ silentError: true }
).then(({ data }) => {
this.updateModsHashCache(data?.modVersions ?? []);
return data?.modVersions?.at(0);
}).catch((): undefined => {
log.error(`Failed to get mod by hash: ${hash}`);
return undefined;
});
}
}
@@ -28,8 +28,6 @@ export class BsModsManagerService {
private readonly linuxService: LinuxService;
private readonly requestService: RequestService;
private manifestMatches: BbmModVersion[];
public static getInstance(): BsModsManagerService {
if (!BsModsManagerService.instance) {
BsModsManagerService.instance = new BsModsManagerService();
@@ -45,7 +43,11 @@ export class BsModsManagerService {
}
private async getModFromHash(hash: string): Promise<BbmModVersion | undefined> {
const mod = await this.beatModsApi.getModByHash(hash);
const mod: BbmModVersion | undefined = await this.beatModsApi.getModByHash(hash)
.catch((error) => {
log.warn("Could not get mod with hash", hash, "cause", error?.message);
return undefined;
});
if(mod?.contentHashes?.some(content => content.path.includes("IPA.exe"))){
return undefined;
@@ -55,7 +57,11 @@ export class BsModsManagerService {
}
private async getModsInDir(version: BSVersion, modsDir: ModsInstallFolder): Promise<BbmModVersion[]> {
private async getModsInDir(
version: BSVersion,
modsDir: ModsInstallFolder,
manifestMatches: BbmModVersion[]
): Promise<BbmModVersion[]> {
const bsPath = await this.bsLocalService.getVersionPath(version);
const modsPath = path.join(bsPath, modsDir);
@@ -66,34 +72,35 @@ export class BsModsManagerService {
const files = await recursiveReadDir(modsPath);
const promises = files.map(async filePath => {
const ext = path.extname(filePath);
const ext = path.extname(filePath);
if (ext !== ".dll" && ext !== ".exe" && ext !== ".manifest") {
return undefined;
}
if (ext !== ".dll" && ext !== ".exe" && ext !== ".manifest") {
return undefined;
}
const hash = await md5File(filePath);
const mod = await this.getModFromHash(hash);
log.info("Getting mod manifest", filePath);
const hash = await md5File(filePath);
const mod = await this.getModFromHash(hash);
if (!mod) {
if (!mod) {
return undefined;
}
if (ext === ".manifest") {
manifestMatches.push(mod);
return undefined;
}
if (modsDir === ModsInstallFolder.LIBS || modsDir === ModsInstallFolder.LIBS_PENDING) {
const manifestIndex = manifestMatches.findIndex(m => m.id === mod.id);
if (manifestIndex < 0) {
log.warn("No matching manifest for", `"${filePath}"`, "with hash:", hash);
return undefined;
}
if (ext === ".manifest") {
this.manifestMatches.push(mod);
return undefined;
}
manifestMatches.splice(manifestIndex, 1);
}
if (filePath.toLowerCase().includes("libs")) {
const manifestIndex = this.manifestMatches.findIndex(m => m.id === mod.id);
if (manifestIndex < 0) {
return undefined;
}
this.manifestMatches.splice(manifestIndex, 1);
}
return mod;
return mod;
});
const results = await Promise.allSettled(promises);
@@ -101,6 +108,8 @@ export class BsModsManagerService {
return results.reduce((mods, mod) => {
if (mod?.status === "fulfilled" && mod?.value) {
mods.push(mod.value);
} else if (mod?.status === "rejected") {
log.error("MOD FAILED", mod);
}
return mods;
}, [] as BbmModVersion[]);
@@ -113,7 +122,10 @@ export class BsModsManagerService {
return undefined;
}
const injectorMd5 = await md5File(injectorPath);
return this.beatModsApi.getModByHash(injectorMd5);
return this.beatModsApi.getModByHash(injectorMd5).catch((error) => {
log.error("Could not get bsipa mod", error?.message);
return undefined;
});
}
private async downloadZip(zipUrl: string): Promise<BsmZipExtractor> {
@@ -345,12 +357,17 @@ export class BsModsManagerService {
}
public async getInstalledMods(version: BSVersion): Promise<BbmModVersion[]> {
this.manifestMatches = [];
const bsipa = await this.getBsipaInstalled(version);
const pluginsMods = await Promise.all([this.getModsInDir(version, ModsInstallFolder.PLUGINS_PENDING), this.getModsInDir(version, ModsInstallFolder.PLUGINS)]);
const libsMods = await Promise.all([this.getModsInDir(version, ModsInstallFolder.LIBS_PENDING), this.getModsInDir(version, ModsInstallFolder.LIBS)]);
const manifestMatches: BbmModVersion[] = [];
const pluginsMods = await Promise.all([
this.getModsInDir(version, ModsInstallFolder.PLUGINS_PENDING, manifestMatches),
this.getModsInDir(version, ModsInstallFolder.PLUGINS, manifestMatches)
]);
const libsMods = await Promise.all([
this.getModsInDir(version, ModsInstallFolder.LIBS_PENDING, manifestMatches),
this.getModsInDir(version, ModsInstallFolder.LIBS, manifestMatches)
]);
const dirMods = pluginsMods.flat().concat(libsMods.flat());
+6 -2
View File
@@ -28,14 +28,18 @@ export class RequestService {
private constructor() {}
public async getJSON<T = unknown>(url: string): Promise<{ data: T; headers: IncomingHttpHeaders }> {
public async getJSON<T = unknown>(url: string, options?: {
silentError?: boolean
}): Promise<{ data: T; headers: IncomingHttpHeaders }> {
try {
// @ts-ignore (ESM is not well supported in this project, We need to move out electron-react-boilerplate, and use Vite)
const res = await got(url, { responseType: 'json', headers: this.baseHeaders });
return { data: res.body as T, headers: res.headers };
} catch (err) {
log.error(`Failed to get JSON from URL: ${url}`, err);
if (options?.silentError !== true) {
log.error(`Failed to get JSON from URL: ${url}`, err);
}
throw err;
}
}