Skip to content

alandtse/MergeMapper

Repository files navigation

MergeMapper SKSE Plugin

A SKSE plugin that maps zmerged plugins. This is intended to be used by other SKSE dlls. Built on CommonlibNG.

Requirements

User Requirements

Register Visual Studio as a Generator

  • Open x64 Native Tools Command Prompt
  • Run cmake
  • Close the cmd window

Building

git clone https://github.com/alandtse/MergeMapper.git
# Open with Visual Studio

License

Apache-2.0

Credits

Developer Use of MergeMapper

General

  1. Copy include/MergeMapperPluginAPI.h and src/MergeMapperPluginAPI.cpp into your project.
  2. Get API doing SKSE PostPostLoad. By default it is in the global g_mergeMapperInterface.
#include "MergeMapperPluginAPI.h"
...
void MessageHandler(SKSE::MessagingInterface::Message* a_message)
{
	if (a_message->type == SKSE::MessagingInterface::kPostPostLoad) {
		MergeMapperPluginAPI::GetMergeMapperInterface001();  // Request interface
		if (g_mergeMapperInterface) { // Use Interface
			const auto version = g_mergeMapperInterface->GetBuildNumber();
			logger::info("Got MergeMapper interface buildnumber {}", version);
		}else
			logger::info("MergeMapper not detected");
	}
}
  1. Use interface to query Mod/formID info.
// Example from Base Object Swapper https://github.com/powerof3/BaseObjectSwapper of finding new formID
			const auto formPair = string::split(a_str, "~"); // splits "FormID~modName" e.g. 0x10C0E3~Skyrim.esm
			if (g_mergeMapperInterface){
				const auto [modName, formID] = g_mergeMapperInterface->GetNewFormID(formPair[1].c_str(), std::stoi(formPair[0], 0, 16));
				return RE::TESDataHandler::GetSingleton()->LookupFormID(formID, (const char*) modName);
			}else{
				return RE::TESDataHandler::GetSingleton()->LookupFormID(std::stoi(formPair[0], 0, 16), formPair[1]);
      }

// Example from MCM Helper https://github.com/alandtse/MCM-Helper of recovering original mod name and formid from merged reference.
	auto modName = std::filesystem::path(filename).stem().string();
	if (g_mergeMapperInterface) {
		modName = std::filesystem::path(filename).filename().string();
		auto formID = a_form->GetFormID() & 0x00FFFFFF;
		auto name = a_form->GetName();
		auto editorID = a_form->GetFormEditorID();
		logger::debug("Attempting to find original mod for {} ({:x}) {}", name, formID, editorID);
		const auto [mergedModName, mergedFormID] = g_mergeMapperInterface->GetOriginalFormID(
			modName.c_str(),
			formID);
		std::string conversion_log = "";
		if (formID && mergedFormID && formID != mergedFormID) {
			conversion_log = std::format("0x{:x}->0x{:x}", formID, mergedFormID);
			formID = mergedFormID;
		}
		const std::string mergedModString{ mergedModName };
		if (!(modName.empty()) && !mergedModString.empty() && modName != mergedModString) {
			if (conversion_log.empty())
				conversion_log = std::format("{}->{}", modName, mergedModString);
			else
				conversion_log = std::format(
					"{}~{}->{}",
					conversion_log,
					modName,
					mergedModString);
			modName = mergedModString;
		}
		modName = modName.substr(0, modName.find(".es"));
		if (!conversion_log.empty())
			logger::debug("\t\tFound original: {}", conversion_log);
	}

Manage dependency with vcpkg

VCPKG is supported using a custom port found in cmake/ports/mergemapper.

  1. Edit vcpkg.json to add mergemapper.
{
  ...
  "dependencies": [
    "mergemapper",
    ...
  ]
}
  1. Ensure cmake support custom ports. Example for setting CmakePresets.json.
        "VCPKG_OVERLAY_PORTS": {
          "type": "STRING",
          "value": "${sourceDir}/cmake/ports/"
        }
  1. Copy cmake/ports/mergemapper to /cmake/ports in your project.
  2. Modify CMakeFiles.txt to include the files.
#...
find_path(MERGEMAPPER_INCLUDE_DIRS "MergeMapperPluginAPI.h")
#...
add_library(
	${PROJECT_NAME}
	SHARED
	${MERGEMAPPER_INCLUDE_DIRS}/MergeMapperPluginAPI.cpp
)
#...
target_include_directories(
	${PROJECT_NAME}
	PRIVATE
    #...
		${MERGEMAPPER_INCLUDE_DIRS}
)