blueskythlikesclouds / DivaModLoader

Mod loader for Hatsune Miku: Project DIVA Mega Mix+
MIT License
269 stars 11 forks source link

DIVA Mod Loader

DIVA Mod Loader (DML) is a mod loader for Hatsune Miku: Project DIVA Mega Mix+. It allows you to make file replacement mods without hassle and provides extra features for convenience.

You can use DIVA Mod Manager (DMM) or d4m as a front-end for DML.

Installation

Some mods may require specific versions of the Visual C++ Redistributable to be installed on your system, even though DIVA Mod Loader itself doesn't need them. To ensure full compatibility with all mods, please install Visual C++ Redistributable Runtimes All-in-One.

Features

Configuration File

config.toml located next to dinput8.dll allows you to configure the behavior of DML.

enabled = true
console = false
mods = "mods"
priority = ["Example Mod 1", "Example Mod 2"]

The priority array is automatically set by mod managers. If you're not using a mod manager, you can delete the priority array from the config file. This will make mods load in alphabetical order from the mods folder, with the mod at the top of the list having the highest priority. This is the default behavior if you have installed DML directly from the GitHub page without a mod manager.

Mod Loading

Each mod contains a config.toml file located within the mod directory.

enabled = true
include = ["."]
dll = ["TemplateMod.dll"]

name = "Template Mod"
description = "This is a template mod!"
version = "1.0"
date = "27.05.2022"
author = "Skyth"

Rest of the properties should be self-explanatory and are not used by DML. They are only used by DMM or d4m to display information about the mod if it wasn't downloaded from GameBanana. However, please make sure to use version/date values in the same format as the given example.

File Replacement

An example mod file structure is as follows:

As you can see, the files are organized in a way that is similar to the CPKs. However, most of the time, you only need to use the main rom directory. Rest of the rom directories are used to replace files for specific languages.

Mod Database Loading

DML can load mod databases which contain entries only relevant to the mod. This makes it possible for multiple mods to co-exist without conflicts. For example, when adding a new song, you can add its PV entry to mod_pv_db.txt file without having to include entries from the base game or other mods.

This works with all database types, mod_obj_db.bin, mod_tex_db.bin, mod_aet_db.bin, etc. However, please note that ID conflicts are still an issue when using this method. Automatic ID conflict fixing is planned to be implemented in the future.

Mod String Array Loading

Mods cannot replace str_array.bin files without overriding each other. As a solution, DML can load mod_str_array.toml files located in the lang2 directory with entries only relevant to the mod.

An example string array file from the Mikudayo/Mikunano mod is as follows:

1273 = "Mikudayo"
cn.1273 = "MIKUDAYO"
kr.1273 = "미쿠다요"
tw.1273 = "MIKUDAYO"
1274 = "Mikunano"
cn.1274 = "MIKUNANO"
kr.1274 = "미쿠나노"
tw.1274 = "MIKUNANO"

An id = "value" pair declares a string for all languages. If you want to declare a string for a specific language, you need to prefix the id with the language code. For example, cn.1273 = "MIKUDAYO" declares the string for Chinese. Language specific strings take precedence over the global ones.

Please make sure all strings are wrapped in quotes.

Grouped String Arrays

When following the original string array file layout, a few limitations arise. For instance, since modules have their specific range starting from 275, adding too many module names outside the range could override customize item names. To solve this issue, DML provides a feature where you can specify strings in separate named arrays by their original ID, without worrying about accidentally overriding other strings.

To demonstrate this format, the previous string array example can be redone as follows:

module.998 = "Mikudayo"
cn.module.998 = "MIKUDAYO"
kr.module.998 = "미쿠다요"
tw.module.998 = "MIKUDAYO"
module.999 = "Mikunano"
cn.module.999 = "MIKUNANO"
kr.module.999 = "미쿠나노"
tw.module.999 = "MIKUNANO"

In this example, 998/999 numbers correspond to the module IDs, instead of the 1273/1274 in the previous example where the required offset number 275 was added to them. Modders are advised to exclusively use this format.

All of the following string types are supported, and the same ID rule applies to all of them:

Please note that both formats can be used at the same time in the same file.

DLL Loading

DML allows you to inject your own code into the game by loading DLL files. Certain functions can be exposed in the DLLs for initialization and per frame updates.

extern "C"
{
    void __declspec(dllexport) PreInit() {}

    void __declspec(dllexport) Init() {}

    void __declspec(dllexport) PostInit() {}

    void __declspec(dllexport) D3DInit(IDXGISwapChain* swapChain, ID3D11Device* device, ID3D11DeviceContext* deviceContext) {}

    void __declspec(dllexport) OnFrame(IDXGISwapChain* swapChain) {}    

    void __declspec(dllexport) OnResize(IDXGISwapChain* swapChain) {}
}

You can omit functions that you don't need to use. They are not required to be declared.

You can use different naming conventions for your functions, eg. PreInit, preInit and pre_init.

The current directory is changed to where the DLL is located before any of the Init functions are called. This is useful if you want to use relative paths.

Please refrain from executing any logic in DllMain, use these exported functions instead. DllMain has too many limitations and issues to be considered reliable.

It’s recommended to statically link the runtime in your DLL. In Visual Studio, you can do this by setting Configuration Properties -> C/C++ -> Code Generation -> Runtime Library to Multi-threaded (/MT) for the release configuration and Multi-threaded Debug (/MTd) for the debug configuration. This ensures that your mod will load properly even if the user doesn't have the required runtime installed on their system.