This is a fork of Pathoschild/Harmony, itself a fork of Harmony 2.4.2. See pardeike/Harmony for documentation and usage.
A post-transpiler IL fixup pass that corrects invalid IL that CoreCLR's JIT silently accepts but Mono's JIT strictly rejects. Runs after all transpilers complete but before IL emission, and fixes:
-
int*float mul type mismatch
- Inserts
conv.r4/conv.i4where CoreCLR silently coerces int*float results but Mono throws "Invalid IL code" errors.
- Inserts
-
Stale
Nullable<T>constructor after call replacement- When a transpiler replaces
Method(Nullable<T>)withMethod(T)without removing the precedingnewobj, the extrahasValuebytes corrupt value type fields on Mono. Uses stack-depth tracking to distinguish this from legitimate Nullable usage.
- When a transpiler replaces
-
Raw local variable index type mismatch
- Transpilers using raw integer indices instead of
LocalBuilderreferences can produce type mismatches that CoreCLR ignores but Mono throwsInvalidProgramExceptionfor. Infers correct types from surrounding IL, declares new typed locals, and redirects references. Handles shifted local indices from game recompilation.
- Transpilers using raw integer indices instead of
-
By-ref parameter handling
- On Mono,
ldnullis incompatible with by-ref parameters (type &), causing "Invalid IL code" errors. Static method patches now use a default-initialized temp local and pass its address instead.
- On Mono,
-
HasDefault parameter attribute stripping
- DMD wrappers don't need default values, and copying them causes Cecil to resolve the parameter type at write time, which fails for game assembly types. This strips
HasDefaultto prevent crashes on Mono.
- DMD wrappers don't need default values, and copying them causes Cecil to resolve the parameter type at write time, which fails for game assembly types. This strips
-
CodeMatcher insert validation fix
- Fixes insert position validation to use
Pos < 0 || Pos > Lengthinstead ofIsInvalid, allowing inserts at the end of the instruction list.
- Fixes insert position validation to use
-
DMD diagnostic dump
- When
InvalidProgramExceptionoccurs during patching, dumps assembly references, mismatched assemblies, and token resolution info for debugging.
- When
- Targets
net8.0only (removednetstandard2.0and multi-targeting) - SDK 8.0.100 with
latestMajorrollforward
Same as Pathoschild's fork: generated method names include the patching Harmony IDs to help troubleshoot error logs:
// with original Harmony
at StardewValley.Farm.resetLocalState_Patch1(Object )
// with fork
at StardewValley.Farm.resetLocalState_PatchedBy<Pathoschild.SmallBeachFarm>(Object )Requires .NET SDK 8.0 or later.
git clone https://github.com/Ekyso/Harmony.git
cd Harmony
dotnet build Lib.Harmony.Thin -c ReleaseOutput in Lib.Harmony.Thin/bin/Release/net8.0/:
0Harmony.dll— Harmony libraryMono.Cecil*.dll— IL/metadata manipulationMonoMod.*.dll— runtime detour and utilities
The SMAPI community uses the Lib.Harmony.Thin version, since SMAPI manages the other
dependencies.