using BepInEx; using BepInEx.Logging; using HarmonyLib; using System; using System.Collections.Generic; using System.IO; using UnityEngine; namespace PartIDRedirection { [BepInPlugin(PluginInfo.PLUGIN_GUID, PluginInfo.PLUGIN_NAME, PluginInfo.PLUGIN_VERSION)] public class PartIDRedirectionPlugin : BaseUnityPlugin { private const string REDIRECT_CONFIG_FILENAME = "PartID.redirects.cfg"; internal static Dictionary IdentifierMappings { get; private set; } internal static ManualLogSource PluginLogger { get; private set; } private void Awake() { PluginLogger = Logger; string configFilePath = Path.Combine(Paths.ConfigPath, REDIRECT_CONFIG_FILENAME); IdentifierMappings = LoadRedirectMappings(configFilePath); Logger.LogInfo($"Loaded {IdentifierMappings.Count} PartID redirect(s) from: {configFilePath}"); try { Harmony harmony = new Harmony(PluginInfo.PLUGIN_GUID); harmony.PatchAll(typeof(PartsDatabasePatch)); harmony.PatchAll(typeof(PartInstancePatch)); Logger.LogInfo("Successfully patched PartsDatabase.GetDesc method"); } catch (Exception ex) { Logger.LogError($"Failed to apply Harmony patches: {ex}"); } } private static Dictionary LoadRedirectMappings(string filePath) { var mappings = new Dictionary(StringComparer.OrdinalIgnoreCase); if (!File.Exists(filePath)) { PluginLogger?.LogWarning($"Redirect configuration file not found: {filePath}"); return mappings; } try { string[] lines = File.ReadAllLines(filePath); int lineNumber = 0; foreach (string rawLine in lines) { lineNumber++; string line = rawLine.Trim(); if (string.IsNullOrEmpty(line) || line.StartsWith("#")) continue; int separatorIndex = line.IndexOf('='); if (separatorIndex <= 0 || separatorIndex >= line.Length - 1) { PluginLogger?.LogWarning($"Invalid format at line {lineNumber}: {line}"); continue; } string oldID = line.Substring(0, separatorIndex).Trim(); string newID = line.Substring(separatorIndex + 1).Trim(); if (string.IsNullOrEmpty(oldID) || string.IsNullOrEmpty(newID)) { PluginLogger?.LogWarning($"Empty ID at line {lineNumber}: {line}"); continue; } if (mappings.ContainsKey(oldID)) { PluginLogger?.LogWarning($"Duplicate mapping for '{oldID}' at line {lineNumber}. Using latest definition."); } mappings[oldID] = newID; } PluginLogger?.LogInfo($"Successfully parsed {mappings.Count} redirect mapping(s)"); } catch (Exception ex) { PluginLogger?.LogError($"Error reading redirect file: {ex.Message}"); } return mappings; } } internal static class PluginInfo { public const string PLUGIN_GUID = "com.anonymus637.partidredirection"; public const string PLUGIN_NAME = "PartID Redirection"; public const string PLUGIN_VERSION = "1.0.0"; } [HarmonyPatch(typeof(PartsDatabase))] internal static class PartsDatabasePatch { [HarmonyPatch("GetDesc", new Type[] { typeof(string), typeof(GetString) })] [HarmonyPrefix] private static void GetDescPrefix(ref string partName) { RedirectPartName(ref partName); } [HarmonyPatch("GetPartDescription")] [HarmonyPrefix] private static void GetPartDescriptionPrefix(ref string partName) { RedirectPartName(ref partName); } private static void RedirectPartName(ref string partName) { if (string.IsNullOrEmpty(partName)) return; string cleanPartName = partName; int newlineIndex = partName.IndexOfAny(new char[] { '\n', '\r' }); if (newlineIndex > 0) { cleanPartName = partName.Substring(0, newlineIndex).Trim(); } if (PartIDRedirectionPlugin.IdentifierMappings.TryGetValue(cleanPartName, out string redirectedIdentifier)) { PartIDRedirectionPlugin.PluginLogger?.LogInfo( $"Redirecting part identifier: '{cleanPartName}' → '{redirectedIdentifier}'" ); if (newlineIndex > 0) { partName = redirectedIdentifier + partName.Substring(newlineIndex); } else { partName = redirectedIdentifier; } } } } [HarmonyPatch(typeof(PartInstance))] internal static class PartInstancePatch { [HarmonyPatch("name", MethodType.Getter)] [HarmonyPostfix] private static void NameGetterPostfix(PartInstance __instance, ref string __result) { if (string.IsNullOrEmpty(__result)) return; string cleanPartName = __result; int newlineIndex = __result.IndexOfAny(new char[] { '\n', '\r' }); if (newlineIndex > 0) { cleanPartName = __result.Substring(0, newlineIndex).Trim(); } if (PartIDRedirectionPlugin.IdentifierMappings.TryGetValue(cleanPartName, out string redirectedIdentifier)) { if (newlineIndex > 0) { __result = redirectedIdentifier + __result.Substring(newlineIndex); } else { __result = redirectedIdentifier; } } } } }