Cleanup of async method names

Add method comments
Reduction of code complexity inside `executeModsAsync()`
Add error message when loaded mod has no `main` property
This commit is contained in:
Dev 2023-10-20 12:23:19 +01:00
parent 33d3e6ce05
commit 3f07fc1bfc
2 changed files with 66 additions and 44 deletions

View File

@ -138,6 +138,7 @@
"modloader-missing_package_json": "Mod (%s) is missing package.json",
"modloader-missing_package_json_property": "Mod {{modName}} package.json requires {{prop}} property",
"modloader-mod_incompatible": "ModLoader: Mod (%s) is incompatible. It must implement at least one of IPostAkiLoadMod, IPostDBLoadMod, IPreAkiLoadMod",
"modloader-mod_has_no_main_property": "ModLoader: Mod (%s) is incompatible. It lacks a 'main' property",
"modloader-async_mod_error": "ModLoader: Error when loading async mod: %s",
"modloader-no_mods_loaded": "Errors were found with mods, NO MODS WILL BE LOADED",
"modloader-outdated_akiversion_field": "Mod %s is not compatible with the current version of AKI. You may encounter issues - no support will be provided!",
@ -145,7 +146,7 @@
"modloader-user_mod_folder_missing": "ModLoader: user/mod folder missing, creating...",
"modloader-mod_order_missing": "ModLoader: order.json is missing, creating...",
"modloader-mod_order_error": "ModLoader: Errors were found in order.json, GOING TO USE DEFAULT LOAD ORDER",
"modloader-mod_order_missing_from_json": "ModLoader: Mod %s is missing from order.json",
"modloader-mod_order_missing_from_json": "ModLoader: Mod %s is missing from order.json, adding",
"modloader-visited": "visited",
"modloader-x_duplicates_found": "One or more duplicate mods found: %s, Only one version of a mod should be loaded",
"openzone-unable_to_find_map": "Unable to add zones to location: %s as it doesn't exist",

View File

@ -57,8 +57,8 @@ export class PreAkiModLoader implements IModLoader
if (globalThis.G_MODS_ENABLED)
{
PreAkiModLoader.container = container;
await this.importMods();
await this.executeMods(container);
await this.importModsAsync();
await this.executeModsAsync(container);
}
}
@ -115,7 +115,7 @@ export class PreAkiModLoader implements IModLoader
return `${this.basepath}${mod}/`;
}
protected async importMods(): Promise<void>
protected async importModsAsync(): Promise<void>
{
if (!this.vfs.exists(this.basepath))
{
@ -207,7 +207,7 @@ export class PreAkiModLoader implements IModLoader
// add mods
for (const mod of sortedMods)
{
await this.addMod(mod);
await this.addModAsync(mod);
}
this.modLoadOrder.setModList(this.imported);
@ -299,7 +299,11 @@ export class PreAkiModLoader implements IModLoader
return loadedMods;
}
/**
* Is the passed in mod compatible with the running server version
* @param mod Mod to check compatibiltiy with AKI
* @returns True if compatible
*/
protected isModCombatibleWithAki(mod: IPackageJsonData): boolean
{
const akiVersion = this.akiConfig.akiVersion;
@ -329,19 +333,28 @@ export class PreAkiModLoader implements IModLoader
return true;
}
protected async executeMods(container: DependencyContainer): Promise<void>
/**
* Execute each mod found in this.imported
* @param container Dependence container to give to mod when it runs
* @returns void promise
*/
protected async executeModsAsync(container: DependencyContainer): Promise<void>
{
// sort mods load order
// Sort mods load order
const source = this.sortModsLoadOrder();
// import mod classes
// Import mod classes
for (const mod of source)
{
if ("main" in this.imported[mod])
if (!this.imported[mod].main)
{
this.logger.error(this.localisationService.getText("modloader-mod_has_no_main_property", mod));
continue;
}
const filepath = `${this.getModPath(mod)}${this.imported[mod].main}`;
// import class
// Import class
const modFilePath = `${process.cwd()}/${filepath}`;
// eslint-disable-next-line @typescript-eslint/no-var-requires
@ -351,9 +364,11 @@ export class PreAkiModLoader implements IModLoader
{
this.logger.error(this.localisationService.getText("modloader-mod_incompatible", mod));
delete this.imported[mod];
return;
}
// Perform async load of mod
if (this.modTypeCheck.isPreAkiLoadAsync(requiredMod.mod))
{
try
@ -365,8 +380,11 @@ export class PreAkiModLoader implements IModLoader
{
this.logger.error(this.localisationService.getText("modloader-async_mod_error", `${err?.message ?? ""}\n${err.stack ?? ""}`));
}
continue;
}
// Perform sync load of mod
if (this.modTypeCheck.isPreAkiLoad(requiredMod.mod))
{
(requiredMod.mod as IPreAkiLoadMod).preAkiLoad(container);
@ -374,8 +392,11 @@ export class PreAkiModLoader implements IModLoader
}
}
}
}
/**
* Read loadorder.json (create if doesnt exist) and return sorted list of mods
* @returns string array of sorted mod names
*/
public sortModsLoadOrder(): string[]
{
// if loadorder.json exists: load it, otherwise generate load order
@ -393,7 +414,7 @@ export class PreAkiModLoader implements IModLoader
* Compile mod and add into class property "imported"
* @param mod Name of mod to compile/add
*/
protected async addMod(mod: string): Promise<void>
protected async addModAsync(mod: string): Promise<void>
{
const modPath = this.getModPath(mod);
const packageData = this.jsonUtil.deserialize<IPackageJsonData>(this.vfs.readFile(`${modPath}/package.json`));
@ -455,13 +476,13 @@ export class PreAkiModLoader implements IModLoader
depIdx++;
}
//if the mod has no extra dependencies return as there's nothing that needs to be done.
// If the mod has no extra dependencies return as there's nothing that needs to be done.
if (dependenciesToInstall.length === 0)
{
return;
}
//if this feature flag is set to false, we warn the user he has a mod that requires extra dependencies and might not work, point them in the right direction on how to enable this feature.
// If this feature flag is set to false, we warn the user he has a mod that requires extra dependencies and might not work, point them in the right direction on how to enable this feature.
if (!this.akiConfig.features.autoInstallModDependencies)
{
this.logger.warning(this.localisationService.getText("modloader-installing_external_dependencies_disabled", {
@ -475,18 +496,18 @@ export class PreAkiModLoader implements IModLoader
return;
}
//temporarily rename package.json because otherwise npm, pnpm and any other package manager will forcefully download all packages in dependencies without any way of disabling this behavior
// Temporarily rename package.json because otherwise npm, pnpm and any other package manager will forcefully download all packages in dependencies without any way of disabling this behavior
this.vfs.rename(`${modPath}/package.json`, `${modPath}/package.json.bak`);
this.vfs.writeFile(`${modPath}/package.json`, "{}");
this.logger.info(this.localisationService.getText("modloader-installing_external_dependencies", {name: pkg.name, author: pkg.author}));
const pnpmPath = path.join(process.cwd(), (globalThis.G_RELEASE_CONFIGURATION ? "Aki_Data/Server/@pnpm/exe" : "node_modules/@pnpm/exe"), (os.platform() === "win32" ? "pnpm.exe" : "pnpm"));
let command: string = `${pnpmPath} install `;
let command = `${pnpmPath} install `;
command += dependenciesToInstall.map(([depName, depVersion]) => `${depName}@${depVersion}`).join(" ");
execSync(command, { cwd: modPath });
// delete the new blank package.json then rename the backup back to the original name
// Delete the new blank package.json then rename the backup back to the original name
this.vfs.removeFile(`${modPath}/package.json`);
this.vfs.rename(`${modPath}/package.json.bak`, `${modPath}/package.json`);
}