Skip to content

Commit

Permalink
Refactor modloader installation
Browse files Browse the repository at this point in the history
Start splitting the massive GenericProfileInstaller class to smaller and
better contained units, starting by creating a dedicated
PackageInstaller class for each of the mod loaders that have special
installation functionality.
  • Loading branch information
MythicManiac committed Aug 3, 2023
1 parent feeac8b commit fde5029
Showing 1 changed file with 82 additions and 46 deletions.
128 changes: 82 additions & 46 deletions src/r2mm/installing/profile_installers/GenericProfileInstaller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,84 @@ import ZipProvider from "../../../providers/generic/zip/ZipProvider";

const basePackageFiles = ["manifest.json", "readme.md", "icon.png"];



abstract class PackageInstaller {
abstract install(mlLocation: string, modLoaderMapping: ModLoaderPackageMapping, profile: Profile): Promise<void>;
// abstract uninstall(): Promise<void>; // TODO: Implement
}


// TODO: Implement
// class InstallRuleInstaller extends PackageInstaller {
// /**
// * The default installer that handles the game-specific install rules
// */
// }


class BepInExInstaller extends PackageInstaller {
/**
* Handles installation of BepInEx
*/
async install(bieLocation: string, modLoaderMapping: ModLoaderPackageMapping, profile: Profile) {
let bepInExRoot: string;
if (modLoaderMapping.rootFolder.trim().length > 0) {
bepInExRoot = path.join(bieLocation, modLoaderMapping.rootFolder);
} else {
bepInExRoot = path.join(bieLocation);
}
for (const item of (await FsProvider.instance.readdir(bepInExRoot))) {
if (!basePackageFiles.includes(item.toLowerCase())) {
if ((await FsProvider.instance.stat(path.join(bepInExRoot, item))).isFile()) {
await FsProvider.instance.copyFile(path.join(bepInExRoot, item), path.join(profile.getPathOfProfile(), item));
} else {
await FsProvider.instance.copyFolder(path.join(bepInExRoot, item), path.join(profile.getPathOfProfile(), item));
}
}
}
}
}


class MelonLoaderInstaller extends PackageInstaller {
/**
* Handles installation of MelonLoader
*/
async install(mlLocation: string, modLoaderMapping: ModLoaderPackageMapping, profile: Profile) {
for (const item of (await FsProvider.instance.readdir(mlLocation))) {
if (!basePackageFiles.includes(item.toLowerCase())) {
if ((await FsProvider.instance.stat(path.join(mlLocation, item))).isFile()) {
await FsProvider.instance.copyFile(path.join(mlLocation, item), path.join(profile.getPathOfProfile(), item));
} else {
await FsProvider.instance.copyFolder(path.join(mlLocation, item), path.join(profile.getPathOfProfile(), item));
}
}
}
}
}


class GodotMLInstaller extends PackageInstaller {
/**
* Handles installation of GodotML
*/
async install(mlLocation: string, modLoaderMapping: ModLoaderPackageMapping, profile: Profile) {
const copyFrom = path.join(mlLocation, "addons", "mod_loader");
const copyTo = path.join(profile.getPathOfProfile(), "addons", "mod_loader");
const fs = FsProvider.instance;

if (await fs.exists(copyFrom)) {
if (!await fs.exists(copyTo)) {
await fs.mkdirs(copyTo);
}
await fs.copyFolder(copyFrom, copyTo);
}
}
}



export default class GenericProfileInstaller extends ProfileInstallerProvider {

private rule: CoreRuleType;
Expand Down Expand Up @@ -151,55 +229,13 @@ export default class GenericProfileInstaller extends ProfileInstallerProvider {
return this.installForManifestV2(mod, profile, cachedLocationOfMod);
}

private async basicModLoaderInstaller(bieLocation: string, modLoaderMapping: ModLoaderPackageMapping, profile: Profile) {
let bepInExRoot: string;
if (modLoaderMapping.rootFolder.trim().length > 0) {
bepInExRoot = path.join(bieLocation, modLoaderMapping.rootFolder);
} else {
bepInExRoot = path.join(bieLocation);
}
for (const item of (await FsProvider.instance.readdir(bepInExRoot))) {
if (!basePackageFiles.includes(item.toLowerCase())) {
if ((await FsProvider.instance.stat(path.join(bepInExRoot, item))).isFile()) {
await FsProvider.instance.copyFile(path.join(bepInExRoot, item), path.join(profile.getPathOfProfile(), item));
} else {
await FsProvider.instance.copyFolder(path.join(bepInExRoot, item), path.join(profile.getPathOfProfile(), item));
}
}
}
}

private async installMelonLoader(mlLocation: string, modLoaderMapping: ModLoaderPackageMapping, profile: Profile) {
for (const item of (await FsProvider.instance.readdir(mlLocation))) {
if (!basePackageFiles.includes(item.toLowerCase())) {
if ((await FsProvider.instance.stat(path.join(mlLocation, item))).isFile()) {
await FsProvider.instance.copyFile(path.join(mlLocation, item), path.join(profile.getPathOfProfile(), item));
} else {
await FsProvider.instance.copyFolder(path.join(mlLocation, item), path.join(profile.getPathOfProfile(), item));
}
}
}
}

private async installGodotML(mlLocation: string, modLoaderMapping: ModLoaderPackageMapping, profile: Profile) {
const copyFrom = path.join(mlLocation, "addons", "mod_loader");
const copyTo = path.join(profile.getPathOfProfile(), "addons", "mod_loader");
const fs = FsProvider.instance;

if (await fs.exists(copyFrom)) {
if (!await fs.exists(copyTo)) {
await fs.mkdirs(copyTo);
}
await fs.copyFolder(copyFrom, copyTo);
}
}

async installModLoader(bieLocation: string, modLoaderMapping: ModLoaderPackageMapping, profile: Profile): Promise<R2Error | null> {
switch (modLoaderMapping.loaderType) {
case PackageLoader.BEPINEX: await this.basicModLoaderInstaller(bieLocation, modLoaderMapping, profile); break;
case PackageLoader.MELON_LOADER: await this.installMelonLoader(bieLocation, modLoaderMapping, profile); break;
case PackageLoader.GODOT_ML: await this.installGodotML(bieLocation, modLoaderMapping, profile); break;
case PackageLoader.NORTHSTAR: await this.basicModLoaderInstaller(bieLocation, modLoaderMapping, profile); break;
case PackageLoader.BEPINEX: await (new BepInExInstaller()).install(bieLocation, modLoaderMapping, profile); break;
case PackageLoader.MELON_LOADER: await (new MelonLoaderInstaller()).install(bieLocation, modLoaderMapping, profile); break;
case PackageLoader.GODOT_ML: await (new GodotMLInstaller()).install(bieLocation, modLoaderMapping, profile); break;
case PackageLoader.NORTHSTAR: await (new BepInExInstaller()).install(bieLocation, modLoaderMapping, profile); break;
}
return Promise.resolve(null);
}
Expand Down

0 comments on commit fde5029

Please sign in to comment.