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:
parent
33d3e6ce05
commit
3f07fc1bfc
@ -138,6 +138,7 @@
|
|||||||
"modloader-missing_package_json": "Mod (%s) is missing package.json",
|
"modloader-missing_package_json": "Mod (%s) is missing package.json",
|
||||||
"modloader-missing_package_json_property": "Mod {{modName}} package.json requires {{prop}} property",
|
"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_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-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-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!",
|
"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-user_mod_folder_missing": "ModLoader: user/mod folder missing, creating...",
|
||||||
"modloader-mod_order_missing": "ModLoader: order.json is 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_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-visited": "visited",
|
||||||
"modloader-x_duplicates_found": "One or more duplicate mods found: %s, Only one version of a mod should be loaded",
|
"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",
|
"openzone-unable_to_find_map": "Unable to add zones to location: %s as it doesn't exist",
|
||||||
|
@ -57,8 +57,8 @@ export class PreAkiModLoader implements IModLoader
|
|||||||
if (globalThis.G_MODS_ENABLED)
|
if (globalThis.G_MODS_ENABLED)
|
||||||
{
|
{
|
||||||
PreAkiModLoader.container = container;
|
PreAkiModLoader.container = container;
|
||||||
await this.importMods();
|
await this.importModsAsync();
|
||||||
await this.executeMods(container);
|
await this.executeModsAsync(container);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,7 +115,7 @@ export class PreAkiModLoader implements IModLoader
|
|||||||
return `${this.basepath}${mod}/`;
|
return `${this.basepath}${mod}/`;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async importMods(): Promise<void>
|
protected async importModsAsync(): Promise<void>
|
||||||
{
|
{
|
||||||
if (!this.vfs.exists(this.basepath))
|
if (!this.vfs.exists(this.basepath))
|
||||||
{
|
{
|
||||||
@ -207,7 +207,7 @@ export class PreAkiModLoader implements IModLoader
|
|||||||
// add mods
|
// add mods
|
||||||
for (const mod of sortedMods)
|
for (const mod of sortedMods)
|
||||||
{
|
{
|
||||||
await this.addMod(mod);
|
await this.addModAsync(mod);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.modLoadOrder.setModList(this.imported);
|
this.modLoadOrder.setModList(this.imported);
|
||||||
@ -299,7 +299,11 @@ export class PreAkiModLoader implements IModLoader
|
|||||||
return loadedMods;
|
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
|
protected isModCombatibleWithAki(mod: IPackageJsonData): boolean
|
||||||
{
|
{
|
||||||
const akiVersion = this.akiConfig.akiVersion;
|
const akiVersion = this.akiConfig.akiVersion;
|
||||||
@ -329,53 +333,70 @@ export class PreAkiModLoader implements IModLoader
|
|||||||
return true;
|
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();
|
const source = this.sortModsLoadOrder();
|
||||||
|
|
||||||
// import mod classes
|
// Import mod classes
|
||||||
for (const mod of source)
|
for (const mod of source)
|
||||||
{
|
{
|
||||||
|
if (!this.imported[mod].main)
|
||||||
if ("main" in this.imported[mod])
|
|
||||||
{
|
{
|
||||||
const filepath = `${this.getModPath(mod)}${this.imported[mod].main}`;
|
this.logger.error(this.localisationService.getText("modloader-mod_has_no_main_property", mod));
|
||||||
// import class
|
|
||||||
const modFilePath = `${process.cwd()}/${filepath}`;
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
continue;
|
||||||
const requiredMod = require(modFilePath);
|
}
|
||||||
|
|
||||||
if (!this.modTypeCheck.isPostV3Compatible(requiredMod.mod))
|
const filepath = `${this.getModPath(mod)}${this.imported[mod].main}`;
|
||||||
|
// Import class
|
||||||
|
const modFilePath = `${process.cwd()}/${filepath}`;
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||||
|
const requiredMod = require(modFilePath);
|
||||||
|
|
||||||
|
if (!this.modTypeCheck.isPostV3Compatible(requiredMod.mod))
|
||||||
|
{
|
||||||
|
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
|
||||||
{
|
{
|
||||||
this.logger.error(this.localisationService.getText("modloader-mod_incompatible", mod));
|
await (requiredMod.mod as IPreAkiLoadModAsync).preAkiLoadAsync(container);
|
||||||
delete this.imported[mod];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.modTypeCheck.isPreAkiLoadAsync(requiredMod.mod))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await (requiredMod.mod as IPreAkiLoadModAsync).preAkiLoadAsync(container);
|
|
||||||
globalThis[mod] = requiredMod;
|
|
||||||
}
|
|
||||||
catch (err)
|
|
||||||
{
|
|
||||||
this.logger.error(this.localisationService.getText("modloader-async_mod_error", `${err?.message ?? ""}\n${err.stack ?? ""}`));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.modTypeCheck.isPreAkiLoad(requiredMod.mod))
|
|
||||||
{
|
|
||||||
(requiredMod.mod as IPreAkiLoadMod).preAkiLoad(container);
|
|
||||||
globalThis[mod] = requiredMod;
|
globalThis[mod] = requiredMod;
|
||||||
}
|
}
|
||||||
|
catch (err)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
globalThis[mod] = requiredMod;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read loadorder.json (create if doesnt exist) and return sorted list of mods
|
||||||
|
* @returns string array of sorted mod names
|
||||||
|
*/
|
||||||
public sortModsLoadOrder(): string[]
|
public sortModsLoadOrder(): string[]
|
||||||
{
|
{
|
||||||
// if loadorder.json exists: load it, otherwise generate load order
|
// 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"
|
* Compile mod and add into class property "imported"
|
||||||
* @param mod Name of mod to compile/add
|
* @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 modPath = this.getModPath(mod);
|
||||||
const packageData = this.jsonUtil.deserialize<IPackageJsonData>(this.vfs.readFile(`${modPath}/package.json`));
|
const packageData = this.jsonUtil.deserialize<IPackageJsonData>(this.vfs.readFile(`${modPath}/package.json`));
|
||||||
@ -455,13 +476,13 @@ export class PreAkiModLoader implements IModLoader
|
|||||||
depIdx++;
|
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)
|
if (dependenciesToInstall.length === 0)
|
||||||
{
|
{
|
||||||
return;
|
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)
|
if (!this.akiConfig.features.autoInstallModDependencies)
|
||||||
{
|
{
|
||||||
this.logger.warning(this.localisationService.getText("modloader-installing_external_dependencies_disabled", {
|
this.logger.warning(this.localisationService.getText("modloader-installing_external_dependencies_disabled", {
|
||||||
@ -475,18 +496,18 @@ export class PreAkiModLoader implements IModLoader
|
|||||||
return;
|
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.rename(`${modPath}/package.json`, `${modPath}/package.json.bak`);
|
||||||
this.vfs.writeFile(`${modPath}/package.json`, "{}");
|
this.vfs.writeFile(`${modPath}/package.json`, "{}");
|
||||||
|
|
||||||
this.logger.info(this.localisationService.getText("modloader-installing_external_dependencies", {name: pkg.name, author: pkg.author}));
|
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"));
|
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(" ");
|
command += dependenciesToInstall.map(([depName, depVersion]) => `${depName}@${depVersion}`).join(" ");
|
||||||
execSync(command, { cwd: modPath });
|
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.removeFile(`${modPath}/package.json`);
|
||||||
this.vfs.rename(`${modPath}/package.json.bak`, `${modPath}/package.json`);
|
this.vfs.rename(`${modPath}/package.json.bak`, `${modPath}/package.json`);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user