/nix-mod-manager

A mod manager for Nix.

Primary LanguageNixGNU General Public License v3.0GPL-3.0

nix-mod-manager

the purest mod manager for home-manager
-•-
getting started · contributing · customization
GitHub License GitHub Repo stars GitHub repo size

🔰 Getting Started

    Requirements to Slay ⚔️
    • Nix, Manager of Packages 🐲
    • Flakes, The Mysterious One ❄️
    • Home Manager, Manager of Home Directories 🏰

First, bust out your favorite text editor and add the repository to your flake:

[^]
        nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";

        home-manager = {
            url = "github:nix-community/home-manager/master";
            inputs.nixpkgs.follows = "nixpkgs";
        };

        nix-mod-manager.url = "github:nowaaru/nix-mod-manager/master";
    };

    outputs = {
        home-manager,
        nix-mod-manager, # 🌟
[v]

Afterwards, add it to your Home Manager configuration either as an import in a module file or directly through the module list:

[^]
        specialArgs = {inherit inputs;};
            modules = [];
        };

        homeConfigurations."rainbow-road" = home-manager.lib.homeManagerConfiguration {
              inherit pkgs;
              extraSpecialArgs = {inherit inputs;};
              modules = [
                nix-mod-manager.homeManagerModules.default # 🌟
                ./home.nix
              ];
        };
[v]

And, voilà! nix-mod-manager is finally ready to roll! To start configuring, make a new module for your Home Manager configuration:

[^]
        };

        homeConfigurations."rainbow-road" = home-manager.lib.homeManagerConfiguration {
              inherit pkgs;
              extraSpecialArgs = {inherit inputs;};
              modules = [
                nix-mod-manager.homeManagerModules.default
                ./nix-mod-manager.nix # 🌟
                ./home.nix
              ];
        };
    };

nix-mod-manager's default module exports the programs.nix-mod-manager module for you to change to your liking. To see what fields you can customize, check out the customization index.

🧰 Library

The nix-mod-manager's lib output contains the nnmm (noire's-nix-mod-manager) library. In this library contains a handful of useful functions for things like creating mod derivations through referencing store files and fetching from remote CDNs.

⚙️ Customization

nix-mod-manager exports the programs.nix-mod-manager module. For the module to work, the enable property must be set to true:

{
    programs.nix-mod-manager = {
        enable = true;
    };
}

A game that is managed is called a client. The property is also aptly named clients and requires an attribute set of attribute sets. Like the module, clients must also be enabled for their mods to be deployed:

{
    programs.nix-mod-manager = {
        enable = true;
            clients = {
                monster-hunter-world = {
                enable = true;
            };
        };
    };
}

A client requires a modsPath and a rootPath to be functional. The rootPath field should be relative to the $HOME (~) directory, and the modsPath field should be relative to the rootPath field. If necessary, you can specify a binaryPath for paired usage with binary mods.

{
    programs.nix-mod-manager = {
        enable = true;
        clients = {
            monster-hunter-world = {
                enable = true;
                modsPath = "nativePC";
                rootPath = ".local/share/Steam/steamapps/common/Monster Hunter World";
                binaryPath = "bin/";
            };
        };
    };
}

A mod manager isn't a mod manager without mods. To get started, we'll be using Dynamic Acrylic Graphics (DAGs) from Home Manager. Mods can either be fetched via turning a store path into a derivation or fetching it through a fetcher. If a mod needs to be placed alongside the binary, the binaryMods DAG should suffice.

with lib.nnmm; with fetchers;
{
    programs.nix-mod-manager = {
        enable = true;
        clients = {
            monster-hunter-world = {
                enable = true;
                modsPath = "nativePC";
                rootPath = ".local/share/Steam/steamapps/common/Monster Hunter World";

                binaryMods = {
                    example-binary-mod-0 = entryAnywhere (fetchGameBanana {
                        name = "my-super-cool-gamebanana-mod";
                        hash = lib.fakeHash;
                    });
                };

                mods = {
                    example-mod-0 = entryAfter ["example-binary-mod-0"] (mkLocalMod {
                        name = "example-mod-0";
                        store-path = /nix/store/...;
                    });
                    example-mod-1 = entryAfter ["example-binary-mod-1"] (mkLocalMod {
                        name = "example-mod-1";
                        store-path = /nix/store/...;
                    });
                };
            };
        };
    };
}

There is also a deploymentType option that allows you to determine how mods are placed in the modsPath. It requires one of "organized" or "loose", but set to "organized" by default. The loose type will drop the artifacts directly into the staging "modsPath", meanwhile the "organized" type will make a numerically sorted list of folders depending on the load order:

with lib.nnmm; with fetchers;
{
    programs.nix-mod-manager = {
        enable = true;
        clients = {
            monster-hunter-world = {
                enable = true;
                modsPath = "nativePC";
                deploymentType = "loose"; # 🌟
                rootPath = ".local/share/Steam/steamapps/common/Monster Hunter World";

                binaryMods = {
                    example-binary-mod-0 = entryAnywhere (fetchGameBanana {
                        name = "my-super-cool-gamebanana-mod";
                        hash = lib.fakeHash;
                    });
                };

                mods = {
                    example-mod-0 = entryAfter ["example-binary-mod-0"] (mkLocalMod {
                        name = "example-mod-0";
                        store-path = /nix/store/...;
                    });
                    example-mod-1 = entryAfter ["example-binary-mod-1"] (mkLocalMod {
                        name = "example-mod-1";
                        store-path = /nix/store/...;
                    });
                };
            };
        };
    };
}

💙 Contributing

Pull Requests
Generally, I'm okay to pull requests as long as the code is good and neat and follows the conventions that the project follows (or lines up closely enough to it). If your pull request takes a while to get merged while there appears to be no backlog, feel free to mention a maintainer or two - but overdoing it makes the whole process slower. It might even get your permissions to contribute revoked!

If you don't know what to make a pull request about, then please don't bother to search for a reason, instead use the project a little bit and figure out something you don't like or something that you think most of the userbase would collectively enjoy. Misspellings and accidental character placements will be addressed at some point, but it is of nothing of urgency to make a pull request for. This isn't a repository you can farm points on!
Issue-making

If you notice something wrong with the project or the way it functions, let me know by making an issue! I'll get on it as quickly as my fingers 💅 and brain 🧠 allows me to - the latter of which likely being the bottleneck.

When making an issue, do be sure to remember the human and remember the newbie. Despite the facade of an anime icon or a mysterious set of blue-tinted buildings with a red room, there's still a human behind that icon, and that human could very well be new to what they're coming across. Newcomers will soon be our replacements, so no reason to bite the hand that will feed us the following day!

Codewriting

While creating nix-mod-manager, I had a very strong intention to use as much Nix as possible and rely as little on shell scripts to get a better grasp of the language, but now I feel it's to upkeep the "nix" aspect of the name. When making contributions, I would prefer and deeply appreciate if contributors used the intended language whenever they can (within reason).