Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix double tooltips and improve SMLHelper compatibility #444

Merged
merged 4 commits into from
Jul 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 47 additions & 5 deletions Nautilus/Patchers/SMLHelperCompatibilityPatcher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,45 @@ namespace Nautilus.Patchers;
// This class can be SAFELY removed if we ever decide to make Nautilus incompatible with SMLHelper (which it already kinda is...)
internal class SMLHelperCompatibilityPatcher
{
private const string SMLHarmonyInstance = "com.ahk1221.smlhelper"; // This string is both the harmony instance & plugin GUID.
public const string SMLHarmonyInstance = "com.ahk1221.smlhelper"; // This string is both the harmony instance & plugin GUID.
public const string QModManagerGUID = "QModManager.QMMLoader";
private const string SMLAssemblyName = "SMLHelper";
private const string SMLHelperModJsonID = "SMLHelper";

private static Assembly _smlHelperAssembly;

internal static void Patch(Harmony harmony)
private static bool? _smlHelperInstalled;

public static bool SMLHelperInstalled
{
if (BepInEx.Bootstrap.Chainloader.PluginInfos.ContainsKey(SMLHarmonyInstance))
get
{
CoroutineHost.StartCoroutine(WaitOnSMLHelperForPatches(harmony));
if (!_smlHelperInstalled.HasValue)
{
_smlHelperInstalled = GetSMLHelperExists();
}
return _smlHelperInstalled.Value;
}
}

private static bool GetSMLHelperExists()
{
#if SUBNAUTICA
return BepInEx.Bootstrap.Chainloader.PluginInfos.ContainsKey(SMLHarmonyInstance);
#elif BELOWZERO
if (!BepInEx.Bootstrap.Chainloader.PluginInfos.TryGetValue(QModManagerGUID, out var qmodManager))
return false;
var qmodServices = Assembly.GetAssembly(qmodManager.Instance.GetType()).GetType("QModManager.API.QModServices");
var qmodServicesInstance = AccessTools.PropertyGetter(qmodServices, "Main").Invoke(null, new object[0]);
return (bool)AccessTools.Method(qmodServices, "ModPresent").Invoke(qmodServicesInstance, new object[] { SMLHelperModJsonID });
#endif
}

internal static void Patch(Harmony harmony)
{
CoroutineHost.StartCoroutine(WaitOnSMLHelperForPatches(harmony));
}

private static IEnumerator WaitOnSMLHelperForPatches(Harmony harmony)
{
// This code is arbitrary but was taken from an older version of SMLHelper so that this patch applies only AFTER has been patched.
Expand All @@ -44,10 +70,18 @@ private static IEnumerator WaitOnSMLHelperForPatches(Harmony harmony)

yield return null;

if (!SMLHelperInstalled)
{
yield break;
}

InternalLogger.Log("Patching SMLHelper compatibility fixes", BepInEx.Logging.LogLevel.Info);

// Finally apply the patches:

UnpatchSMLOptionsMethods(harmony);
FixSMLOptionsException(harmony);
UnpatchSMLTooltipPatches(harmony);
}

private static void UnpatchSMLOptionsMethods(Harmony harmony)
Expand Down Expand Up @@ -114,6 +148,14 @@ private static bool ChangeAdjusterComponentPrefix(object __instance, ref Type __
return false;
}

// We don't want duplicate tooltips!!
private static void UnpatchSMLTooltipPatches(Harmony harmony)
{
harmony.Unpatch(AccessTools.Method(typeof(TooltipFactory), nameof(TooltipFactory.BuildTech)), HarmonyPatchType.Postfix, SMLHarmonyInstance);
harmony.Unpatch(AccessTools.Method(typeof(TooltipFactory), nameof(TooltipFactory.ItemCommons)), HarmonyPatchType.Postfix, SMLHarmonyInstance);
harmony.Unpatch(AccessTools.Method(typeof(TooltipFactory), nameof(TooltipFactory.CraftRecipe)), HarmonyPatchType.Postfix, SMLHarmonyInstance);
}

private static Assembly GetSMLAssembly()
{
if (_smlHelperAssembly != null)
Expand All @@ -130,7 +172,7 @@ private static Assembly GetSMLAssembly()
return _smlHelperAssembly;
}

private static Type GetSMLType(string typeName)
internal static Type GetSMLType(string typeName)
{
var assembly = GetSMLAssembly();
return assembly.GetType(typeName);
Expand Down
84 changes: 73 additions & 11 deletions Nautilus/Patchers/TooltipPatcher.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System.IO;
using System.IO;
using System.Reflection;
using System.Text;
using BepInEx.Logging;
Expand All @@ -12,6 +12,11 @@ internal class TooltipPatcher
{
internal static bool DisableEnumIsDefinedPatch = false;

// For compatibility purposes:

private static MethodInfo _smlHelperIsVanillaTechTypeMethod;
private static MethodInfo _smlHelperWriteModNameFromTechTypeMethod;

internal static void Patch(Harmony harmony)
{
Initialize();
Expand Down Expand Up @@ -45,25 +50,82 @@ internal static void CustomTooltip(StringBuilder sb, TechType techType)
WriteSpace(sb);
}

if (techType.IsDefinedByDefault())
// Compatibility for SMLHelper if it is installed
if (SMLHelperCompatibilityPatcher.SMLHelperInstalled)
{
var safeToUseSMLMethods = EnsureSMLHelperMethodReferences();

if (techType.IsDefinedByDefault())
{
if (safeToUseSMLMethods && !(bool)_smlHelperIsVanillaTechTypeMethod.Invoke(null, new object[] { techType }))
{
_smlHelperWriteModNameFromTechTypeMethod.Invoke(null, new object[] { sb, techType });
}
else
{
#if SUBNAUTICA
WriteModName(sb, "Subnautica");
#elif BELOWZERO
WriteModName(sb, "BelowZero");
#endif
}
}
else if (EnumHandler.TryGetOwnerAssembly(techType, out Assembly assembly))
{
WriteModNameFromAssembly(sb, assembly);
}
else
{
WriteModNameError(sb, "Unknown Mod", "Item added without Nautilus");
}
}
// Otherwise use a more basic method of doing things
else
{
if (techType.IsDefinedByDefault())
#if SUBNAUTICA
WriteModName(sb, "Subnautica");
WriteModName(sb, "Subnautica");
#elif BELOWZERO
WriteModName(sb, "BelowZero");
#endif
else if (EnumHandler.TryGetOwnerAssembly(techType, out Assembly assembly))
else if (EnumHandler.TryGetOwnerAssembly(techType, out Assembly assembly))
{
WriteModNameFromAssembly(sb, assembly);
}
else
{
WriteModNameError(sb, "Unknown Mod", "Item added without Nautilus");
}
}
}

// For SMLHelper compatibility only
private static bool EnsureSMLHelperMethodReferences()
{
if (_smlHelperIsVanillaTechTypeMethod == null)
{
WriteModNameFromAssembly(sb, assembly);
_smlHelperIsVanillaTechTypeMethod = AccessTools.Method(SMLHelperCompatibilityPatcher.GetSMLType("SMLHelper.V2.Patchers.TooltipPatcher"), "IsVanillaTechType");
if (_smlHelperIsVanillaTechTypeMethod == null)
{
InternalLogger.Error("Failed to locate SMLHelper's TooltipPatcher.IsVanillaTechType method!");
return false;
}
}
else
if (_smlHelperWriteModNameFromTechTypeMethod == null)
{
WriteModNameError(sb, "Unknown Mod", "Item added without Nautilus");
_smlHelperWriteModNameFromTechTypeMethod = AccessTools.Method(SMLHelperCompatibilityPatcher.GetSMLType("SMLHelper.V2.Patchers.TooltipPatcher"), "WriteModNameFromTechType");
if (_smlHelperWriteModNameFromTechTypeMethod == null)
{
InternalLogger.Error("Failed to locate SMLHelper's TooltipPatcher.WriteModNameFromTechType method!");
return false;
}
}
return true;
}

internal static void WriteTechType(StringBuilder sb, TechType techType)
{
sb.AppendFormat("\n\n<size=19><color=#808080FF>{0} ({1})</color></size>", techType.AsString(), (int)techType);
sb.AppendFormat("\n\n<size=19><color=#808080FF>{0} ({1})</color></size>", techType.AsString(), (int) techType);
}
internal static void WriteModName(StringBuilder sb, string text)
{
Expand All @@ -77,7 +139,7 @@ internal static void WriteModNameFromAssembly(StringBuilder sb, Assembly assembl
{
string modName = assembly.GetName().Name;

if(string.IsNullOrEmpty(modName))
if (string.IsNullOrEmpty(modName))
{
WriteModNameError(sb, "Unknown Mod", "Mod could not be determined");
}
Expand Down Expand Up @@ -136,7 +198,7 @@ internal static void Initialize()
}

Initialized = true;

var nautilusFolder = Path.Combine(BepInEx.Paths.ConfigPath, Assembly.GetExecutingAssembly().GetName().Name);
Directory.CreateDirectory(nautilusFolder);

Expand Down