Skip to content

Commit 0804e11

Browse files
committed
add option to disable Harmony/MonoMod fix
1 parent 690b3ef commit 0804e11

5 files changed

Lines changed: 40 additions & 10 deletions

File tree

docs/release-notes.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
# Release notes
44
## Upcoming release
55
* For players:
6+
* Added option to disable Harmony/MonoMod fix for players with certain crashes.
7+
_This should only be changed if no installed mods use Harmony._
68
* Fixed split-screen crash for non-English players when mods added translated variants of content assets.
79
* SMAPI no longer rewrites mods which use Harmony 1.x, to help reduce Harmony crashes.
810
_This should affect very few mods that still work otherwise, and any Harmony mod updated after July 2021 should be unaffected._

src/SMAPI/Framework/Logging/LogManager.cs

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,8 @@ public void LogSettingsHeader(SConfig settings)
261261
/// <param name="skippedMods">The mods which could not be loaded.</param>
262262
/// <param name="logParanoidWarnings">Whether to log issues for mods which directly use potentially sensitive .NET APIs like file or shell access.</param>
263263
/// <param name="logTechnicalDetailsForBrokenMods">Whether to include more technical details about broken mods in the TRACE logs. This is mainly useful for creating compatibility rewriters.</param>
264-
public void LogModInfo(IModMetadata[] loaded, IModMetadata[] loadedContentPacks, IModMetadata[] loadedMods, IModMetadata[] skippedMods, bool logParanoidWarnings, bool logTechnicalDetailsForBrokenMods)
264+
/// <param name="hasHarmonyFix">Whether Harmony was fixed to work with Stardew Valley.</param>
265+
public void LogModInfo(IModMetadata[] loaded, IModMetadata[] loadedContentPacks, IModMetadata[] loadedMods, IModMetadata[] skippedMods, bool logParanoidWarnings, bool logTechnicalDetailsForBrokenMods, bool hasHarmonyFix)
265266
{
266267
// log loaded mods
267268
this.Monitor.Log($"Loaded {loadedMods.Length} mods" + (loadedMods.Length > 0 ? ":" : "."), LogLevel.Info);
@@ -300,7 +301,7 @@ public void LogModInfo(IModMetadata[] loaded, IModMetadata[] loadedContentPacks,
300301
}
301302

302303
// log mod warnings
303-
this.LogModWarnings(loaded, skippedMods, logParanoidWarnings, logTechnicalDetailsForBrokenMods);
304+
this.LogModWarnings(loaded, skippedMods, logParanoidWarnings, logTechnicalDetailsForBrokenMods, hasHarmonyFix);
304305
}
305306

306307
/// <inheritdoc />
@@ -318,8 +319,9 @@ public void Dispose()
318319
/// <param name="skippedMods">The mods which could not be loaded.</param>
319320
/// <param name="logParanoidWarnings">Whether to log issues for mods which directly use potentially sensitive .NET APIs like file or shell access.</param>
320321
/// <param name="logTechnicalDetailsForBrokenMods">Whether to include more technical details about broken mods in the TRACE logs. This is mainly useful for creating compatibility rewriters.</param>
322+
/// <param name="hasHarmonyFix">Whether Harmony was fixed to work with Stardew Valley.</param>
321323
[SuppressMessage("ReSharper", "ConditionalAccessQualifierIsNonNullableAccordingToAPIContract", Justification = "Manifests aren't guaranteed non-null at this point in the loading process.")]
322-
private void LogModWarnings(IEnumerable<IModMetadata> mods, IModMetadata[] skippedMods, bool logParanoidWarnings, bool logTechnicalDetailsForBrokenMods)
324+
private void LogModWarnings(IEnumerable<IModMetadata> mods, IModMetadata[] skippedMods, bool logParanoidWarnings, bool logTechnicalDetailsForBrokenMods, bool hasHarmonyFix)
323325
{
324326
// get mods with warnings
325327
IModMetadata[] modsWithWarnings = mods
@@ -390,17 +392,29 @@ private void LogModWarnings(IEnumerable<IModMetadata> mods, IModMetadata[] skipp
390392
"errors, or crashes in-game."
391393
);
392394

395+
// missing Harmony fix
396+
if (!hasHarmonyFix)
397+
{
398+
this.LogModWarningGroup(modsWithWarnings, ModWarning.PatchesGame, LogLevel.Warn, "Patched game code without Harmony fix",
399+
$"These mods directly change the game code using Harmony, but you disabled the {nameof(SConfig.FixHarmony)} option.",
400+
"The game will probably crash soon."
401+
);
402+
}
403+
393404
// changes serializer
394405
this.LogModWarningGroup(modsWithWarnings, ModWarning.ChangesSaveSerializer, LogLevel.Warn, "Changed save serializer",
395406
"These mods change the save serializer. They may corrupt your save files, or make them unusable if",
396407
"you uninstall these mods."
397408
);
398409

399410
// patched game code
400-
this.LogModWarningGroup(modsWithWarnings, ModWarning.PatchesGame, LogLevel.Info, "Patched game code",
401-
"These mods directly change the game code. They're more likely to cause errors or bugs in-game; if",
402-
"your game has issues, try removing these first. Otherwise you can ignore this warning."
403-
);
411+
if (hasHarmonyFix)
412+
{
413+
this.LogModWarningGroup(modsWithWarnings, ModWarning.PatchesGame, LogLevel.Info, "Patched game code",
414+
"These mods directly change the game code. They're more likely to cause errors or bugs in-game; if",
415+
"your game has issues, try removing these first. Otherwise you can ignore this warning."
416+
);
417+
}
404418

405419
// unvalidated update tick
406420
this.LogModWarningGroup(modsWithWarnings, ModWarning.UsesUnvalidatedUpdateTick, LogLevel.Info, "Bypassed safety checks",

src/SMAPI/Framework/Models/SConfig.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ internal class SConfig
2424
[nameof(LogNetworkTraffic)] = false,
2525
[nameof(LogTechnicalDetailsForBrokenMods)] = false,
2626
[nameof(RewriteMods)] = true,
27+
[nameof(FixHarmony)] = true,
2728
[nameof(UseCaseInsensitivePaths)] = Constants.Platform is Platform.Android or Platform.Linux,
2829
[nameof(SuppressHarmonyDebugMode)] = true
2930
};
@@ -71,6 +72,9 @@ internal class SConfig
7172
/// <summary>Whether SMAPI should rewrite mods for compatibility.</summary>
7273
public bool RewriteMods { get; set; }
7374

75+
/// <summary>Whether to apply fixes to Harmony so it works with Stardew Valley.</summary>
76+
public bool FixHarmony { get; set; }
77+
7478
/// <summary>Whether to make SMAPI file APIs case-insensitive, even on Linux.</summary>
7579
public bool UseCaseInsensitivePaths { get; set; }
7680

@@ -109,6 +113,7 @@ internal class SConfig
109113
/// <param name="webApiBaseUrl"><inheritdoc cref="WebApiBaseUrl" path="/summary" /></param>
110114
/// <param name="verboseLogging"><inheritdoc cref="VerboseLogging" path="/summary" /></param>
111115
/// <param name="rewriteMods"><inheritdoc cref="RewriteMods" path="/summary" /></param>
116+
/// <param name="fixHarmony"><inheritdoc cref="FixHarmony" path="/summary" /></param>
112117
/// <param name="useCaseInsensitivePaths"><inheritdoc cref="UseCaseInsensitivePaths" path="/summary" /></param>
113118
/// <param name="logNetworkTraffic"><inheritdoc cref="LogNetworkTraffic" path="/summary" /></param>
114119
/// <param name="logTechnicalDetailsForBrokenMods"><inheritdoc cref="LogTechnicalDetailsForBrokenMods" path="/summary" /></param>
@@ -117,7 +122,7 @@ internal class SConfig
117122
/// <param name="suppressUpdateChecks"><inheritdoc cref="SuppressUpdateChecks" path="/summary" /></param>
118123
/// <param name="modsToLoadEarly"><inheritdoc cref="ModsToLoadEarly" path="/summary" /></param>
119124
/// <param name="modsToLoadLate"><inheritdoc cref="ModsToLoadLate" path="/summary" /></param>
120-
public SConfig(bool developerMode, bool? checkForUpdates, bool? listenForConsoleInput, bool? paranoidWarnings, bool? useBetaChannel, string gitHubProjectName, string webApiBaseUrl, string[]? verboseLogging, bool? rewriteMods, bool? useCaseInsensitivePaths, bool? logNetworkTraffic, bool? logTechnicalDetailsForBrokenMods, ColorSchemeConfig consoleColors, bool? suppressHarmonyDebugMode, string[]? suppressUpdateChecks, string[]? modsToLoadEarly, string[]? modsToLoadLate)
125+
public SConfig(bool developerMode, bool? checkForUpdates, bool? listenForConsoleInput, bool? paranoidWarnings, bool? useBetaChannel, string gitHubProjectName, string webApiBaseUrl, string[]? verboseLogging, bool? rewriteMods, bool? fixHarmony, bool? useCaseInsensitivePaths, bool? logNetworkTraffic, bool? logTechnicalDetailsForBrokenMods, ColorSchemeConfig consoleColors, bool? suppressHarmonyDebugMode, string[]? suppressUpdateChecks, string[]? modsToLoadEarly, string[]? modsToLoadLate)
121126
{
122127
this.DeveloperMode = developerMode;
123128
this.CheckForUpdates = checkForUpdates ?? (bool)SConfig.DefaultValues[nameof(this.CheckForUpdates)];
@@ -128,6 +133,7 @@ public SConfig(bool developerMode, bool? checkForUpdates, bool? listenForConsole
128133
this.WebApiBaseUrl = webApiBaseUrl;
129134
this.VerboseLogging = new HashSet<string>(verboseLogging ?? Array.Empty<string>(), StringComparer.OrdinalIgnoreCase);
130135
this.RewriteMods = rewriteMods ?? (bool)SConfig.DefaultValues[nameof(this.RewriteMods)];
136+
this.FixHarmony = fixHarmony ?? (bool)SConfig.DefaultValues[nameof(this.FixHarmony)];
131137
this.UseCaseInsensitivePaths = useCaseInsensitivePaths ?? (bool)SConfig.DefaultValues[nameof(this.UseCaseInsensitivePaths)];
132138
this.LogNetworkTraffic = logNetworkTraffic ?? (bool)SConfig.DefaultValues[nameof(this.LogNetworkTraffic)];
133139
this.LogTechnicalDetailsForBrokenMods = logTechnicalDetailsForBrokenMods ?? (bool)SConfig.DefaultValues[nameof(this.LogTechnicalDetailsForBrokenMods)];

src/SMAPI/Framework/SCore.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,8 @@ public void RunInteractively()
280280
GameRunner.instance = this.Game;
281281

282282
// fix Harmony for mods
283-
MiniMonoModHotfix.Apply();
283+
if (this.Settings.FixHarmony)
284+
MiniMonoModHotfix.Apply();
284285

285286
// set window titles
286287
this.UpdateWindowTitles();
@@ -1743,7 +1744,7 @@ private void LoadMods(IModMetadata[] mods, JsonHelper jsonHelper, ContentCoordin
17431744
this.ModRegistry.AreAllModsLoaded = true;
17441745

17451746
// log mod info
1746-
this.LogManager.LogModInfo(loaded, loadedContentPacks, loadedMods, skippedMods.ToArray(), this.Settings.ParanoidWarnings, this.Settings.LogTechnicalDetailsForBrokenMods);
1747+
this.LogManager.LogModInfo(loaded, loadedContentPacks, loadedMods, skippedMods.ToArray(), this.Settings.ParanoidWarnings, this.Settings.LogTechnicalDetailsForBrokenMods, this.Settings.FixHarmony);
17471748

17481749
// initialize translations
17491750
this.ReloadTranslations(loaded);

src/SMAPI/SMAPI.config.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,13 @@ in future SMAPI versions.
5353
*/
5454
"RewriteMods": true,
5555

56+
/**
57+
* Whether to fix the library mods use to patch game code, so it works with Stardew Valley.
58+
*
59+
* If you disable this, mods which use Harmony are likely to cause game crashes.
60+
*/
61+
"FixHarmony": true,
62+
5663
/**
5764
* Whether to make SMAPI file APIs case-insensitive (even if the filesystem is case-sensitive).
5865
*

0 commit comments

Comments
 (0)