D2RMM Mod Manager

repository·master·Indexed 41 days ago

https://github.com/olegbl/d2rmm

A mod manager for Diablo II: Resurrected featuring a native library (CascLib) for interacting with game files. It provides a ModAPI for creating mods using JavaScript or TypeScript, supporting JSON and TSV file manipulation, dynamic configuration bindings, and localized logging via ConsoleAPI.

Tokens
6.7K
Snippets
28
Records
33
Agent score
52%

What's inside D2RMM

  1. Understand the D2RMM mod runtime globals

    master

    When a D2RMM mod (mod.js or mod.ts) runs, it is provided with three global variables that allow you to interact with the manager, the user's configuration, and the console:

    • D2RMM: An object of type ModAPI used to perform file operations and check environment versions.
    • config: An object of type ModConfigValue containing the values selected by the user in the mod's configuration UI.
    • console: An object of type ConsoleAPI for logging information.

    Example usage:

    if (D2RMM.getVersion() < 1.5) {
      throw new Error('This mod requires D2RMM version 1.5 or newer!');
    }
    
    D2RMM.writeJson('local\lng\strings\foo.json', {foo: 'foo!'});
    
    if (config.isBarEnabled) {
      console.log('Feature bar is enabled!');
      D2RMM.writeJson('local\lng\strings\bar.json', {bar: 'bar!'});
    }
    if (D2RMM.getVersion() < 1.5) {
      throw new Error('This mod requires D2RMM version 1.5 or newer!');
    }
    
    D2RMM.writeJson('local\lng\strings\foo.json', {foo: 'foo!'});
    
    if (config.isBarEnabled) {
      console.log('Feature bar is enabled!');
      D2RMM.writeJson('local\lng\strings\bar.json', {bar: 'bar!'});
    }
  2. Use TypeScript for D2RMM mods

    master

    D2RMM supports TypeScript. To use it, simply create a mod.ts file instead of mod.js.

    Type Checking & Auto Completion

    If you are developing directly inside the D2RMM mods directory, type checking and auto-completion should work automatically in IDEs like VS Code due to the types.d.ts file located in the D2RMM directory.

    If you are developing in a separate workspace, copy the types.d.ts file from the D2RMM directory into your project to enable these features.

    Multi-File Support

    TypeScript mods support ES6 import/export syntax, allowing you to split your mod logic across multiple files.

  3. Create a new D2RMM mod

    master

    To create a new mod, create a new folder within the <D2RMM>/mods/ directory (e.g., <D2RMM>/mods/MyNewMod/). Inside this folder, you must create two files:

    1. mod.json: A plaintext file that describes your mod (name, author, version, and user-customizable options).
    2. mod.js (or mod.ts): A JavaScript or TypeScript file that uses the D2RMM API to modify game files during the installation process.
    mkdir <D2RMM>/mods/MyNewMod
    cd <D2RMM>/mods/MyNewMod
    touch mod.json mod.js
  4. Build D2RMM from source

    master

    To build D2RMM from source, ensure you have Node v22 installed (using nvm is recommended). Follow these steps to clone, install dependencies, and run or package the application:

    1. Clone the repository and enter the directory.
    2. Install dependencies using yarn install.
    3. Use yarn start to run the manager in debug mode.
    4. Use yarn package to create a release build.

    Additional build commands:

    • yarn docs: Build the documentation site.
    • yarn build:updater: Build the auto-updater.
    • yarn build:casclib: Build the CascLib native library.
    • yarn build:config-schema: Build the JSON schema for mod configurations.
    git clone <repository_url>
    cd d2rmm
    yarn install
    yarn start
    # or
    yarn package
  5. Experimental macOS support (arm64 only)

    master

    macOS support is currently experimental and not officially supported.

    • Supported Hardware: Apple Silicon Macs (M1, M2, M3, M4) via .dmg releases.
    • Unsupported Hardware: Intel-based Macs are not supported.
    • Building for macOS: Follow the standard build steps. Running yarn package will generate a .dmg file located in release/build/.
  6. Run D2R with D2RMM on macOS and Linux

    master

    Because Diablo II: Resurrected does not have native macOS or Linux versions, you must use compatibility tools like CrossOver (macOS) or Lutris (Linux) to run the game.

    To ensure D2RMM works correctly with the game, you must launch Diablo II: Resurrected with the following run options:

    -mod D2RMM -txt

    -mod D2RMM -txt
  7. Experimental Linux support

    master

    Linux support is currently experimental and not officially supported.

    • Distribution: Pre-built releases are available as .tar.gz archives.
    • Building for Linux: Follow the standard build steps. Running yarn package will generate a .tar.gz archive located in release/build/.
  8. Configure your mod with mod.json

    master

    The mod.json file defines the metadata for your mod. It follows the ModConfig interface. To enable IDE validation and auto-completion for your configuration schema, you can include a $schema field pointing to a config.json file.

    Example mod.json:

    {
      "$schema": "../config-schema.json",
      "name": "My New Mod",
      "description": "Best mod ever. Does great things! This is a terrible description.",
      "author": "myname",
      "website": "https://www.nexusmods.com/diablo2resurrected/mods/123456789",
      "version": "1.0"
    }
    {
      "$schema": "../config-schema.json",
      "name": "My New Mod",
      "description": "Best mod ever. Does great things! This is a terrible description.",
      "author": "myname",
      "website": "https://www.nexusmods.com/diablo2resurrected/mods/123456789",
      "version": "1.0"
    }
  9. How ModConfigSection works

    master

    A ModConfigSection is a container used to group related configuration fields or other sections in the UI.

    Properties:

    • type: Must be 'section'.
    • name: The display name of the section.
    • description: A tooltip description.
    • children: An array of ModConfigFieldOrSection contained within this section.
    • defaultExpanded: Whether the section is expanded by default.
    • allowToggleAll: If true, a 'toggle all' button appears if all children are checkboxes.
    • visible: A Binding<boolean> to control visibility.
    • defaultValue / overrideValue: Used to control the section's own checkbox (if the section has a value other than null). Note that defaultValue is evaluated once at load time and is not reactive; use overrideValue for reactive forcing.
  10. Use I18nError for localized error reporting

    master

    I18nError is a specialized subtype of the standard Error object used to carry a localized error chain. This allows the renderer process to display a fully localized version of an error and its surrounding context.

    • The standard error.message property preserves the English version for the d2rmm.log file.
    • The __d2rmm_i18n_list property contains an array of ConsoleArg objects (typically I18nConsoleArg markers produced by tl()).
    • The list is ordered from the outermost context (index 0) to the innermost error.
    • The renderer uses this list to translate and build the localized error display for the user.
    export type I18nError = Error & {
      __d2rmm_i18n_list: ConsoleArg[];
    };
  11. Understand the I18nConsoleArg structure for localized logging

    master

    When using the tl() function (implied) to produce structured internationalization markers, the resulting object is of type I18nConsoleArg. This object is designed to pass through the IPC bridge to allow different processes to resolve the same key into different languages:

    • Main process (d2rmm.log): Resolves the key to English using en-US.json interpolation.
    • Renderer process (Logs tab): Resolves the key to the user's current locale via i18next.

    To include extra context (like stack traces or error details) that should appear unchanged in both locations, pass them as additional arguments to console.log, console.warn, or console.error alongside the i18n marker.

    export type I18nConsoleArg = {
      __d2rmm_i18n: true;
      key: string;
      args?: Record<string, string | number>;
    };